From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Mans Rullgard Newsgroups: gmane.comp.audio.sox.devel Subject: [PATCH] Add support for reading DSF files Date: Wed, 5 Aug 2015 20:28:38 +0100 Message-ID: <1438802918-23842-1-git-send-email-mans@mansr.com> Reply-To: sox-devel@lists.sourceforge.net NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Trace: ger.gmane.org 1438802948 3869 80.91.229.3 (5 Aug 2015 19:29:08 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 5 Aug 2015 19:29:08 +0000 (UTC) To: sox-devel@lists.sourceforge.net Original-X-From: sox-devel-bounces@lists.sourceforge.net Wed Aug 05 21:29:00 2015 Return-path: Envelope-to: gcasd-sox-devel@m.gmane.org X-ACL-Warn: X-Mailer: git-send-email 2.5.0 X-Spam-Score: -0.1 (/) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.1 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain X-Headers-End: 1ZN4Mr-0004FC-HH X-BeenThere: sox-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: sox-devel-bounces@lists.sourceforge.net Xref: news.gmane.org gmane.comp.audio.sox.devel:410 Archived-At: Received: from lists.sourceforge.net ([216.34.181.88]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1ZN4N1-0002xB-Li for gcasd-sox-devel@m.gmane.org; Wed, 05 Aug 2015 21:28:59 +0200 Received: from localhost ([127.0.0.1] helo=sfs-ml-3.v29.ch3.sourceforge.com) by sfs-ml-3.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1ZN4Mw-0001ia-5c; Wed, 05 Aug 2015 19:28:54 +0000 Received: from sog-mx-3.v43.ch3.sourceforge.com ([172.29.43.193] helo=mx.sourceforge.net) by sfs-ml-3.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1ZN4Mv-0001iU-Dy for sox-devel@lists.sourceforge.net; Wed, 05 Aug 2015 19:28:53 +0000 Received: from unicorn.mansr.com ([81.2.72.234]) by sog-mx-3.v43.ch3.sourceforge.com with esmtp (Exim 4.76) id 1ZN4Mr-0004FC-HH for sox-devel@lists.sourceforge.net; Wed, 05 Aug 2015 19:28:53 +0000 Received: by unicorn.mansr.com (Postfix, from userid 51770) id 0FD131538A; Wed, 5 Aug 2015 20:28:44 +0100 (BST) This adds support for reading DSD data from DSF files as specified by http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf The 1-bit DSD samples are simply unpacked to sox_sample_t values of maximum or minimum value. The "rate" filter can be used directly on this to obtain usable PCM samples. The format also allows 8-bit DSD-wide samples. Such files are not supported by this patch. DSF files may include an ID3v2 metadata tag, which is not handled here. --- src/Makefile.am | 2 +- src/dsf.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/formats.h | 1 + 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 src/dsf.c diff --git a/src/Makefile.am b/src/Makefile.am index 7cceaaf..462d46d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,7 +121,7 @@ libsox_la_SOURCES += raw-fmt.c s1-fmt.c s2-fmt.c s3-fmt.c \ lu-fmt.c 8svx.c aiff-fmt.c aifc-fmt.c au.c avr.c cdr.c cvsd-fmt.c \ dvms-fmt.c dat.c hcom.c htk.c maud.c prc.c sf.c smp.c \ sounder.c soundtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \ - ima_rw.c ima_rw.h wav.c wve.c xa.c nulfile.c f4-fmt.c f8-fmt.c gsrt.c + ima_rw.c ima_rw.h wav.c wve.c xa.c nulfile.c f4-fmt.c f8-fmt.c gsrt.c dsf.c libsox_la_LIBADD += @GSM_LIBS@ @LIBGSM_LIBADD@ libsox_la_LIBADD += @LPC10_LIBS@ @LIBLPC10_LIBADD@ diff --git a/src/dsf.c b/src/dsf.c new file mode 100644 index 0000000..04864e1 --- /dev/null +++ b/src/dsf.c @@ -0,0 +1,209 @@ +/* DSF file support + * + * Copyright (c) 2015 Mans Rullgard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library 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 Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* File format specification available at + * http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf + */ + +#include +#include "sox_i.h" + +struct dsf { + uint64_t file_size; + uint64_t metadata; + uint32_t version; + uint32_t format_id; + uint32_t chan_type; + uint32_t chan_num; + uint32_t sfreq; + uint32_t bps; + uint64_t scount; + uint32_t block_size; + + uint32_t block_pos; + uint8_t *block; + uint64_t read_samp; +}; + +#define TAG(a, b, c, d) ((a) | (b) << 8 | (c) << 16 | (d) << 24) + +#define DSF_TAG TAG('D', 'S', 'D', ' ') +#define FMT_TAG TAG('f', 'm', 't', ' ') +#define DATA_TAG TAG('d', 'a', 't', 'a') + +static int dsf_startread(sox_format_t *ft) +{ + struct dsf *dsf = ft->priv; + uint32_t magic; + uint64_t csize; + uint32_t v; + + if (lsx_readdw(ft, &magic) || magic != DSF_TAG) { + lsx_fail_errno(ft, SOX_EHDR, "DSF signature not found"); + return SOX_EHDR; + } + + if (lsx_readqw(ft, &csize) || csize != 28) { + lsx_fail_errno(ft, SOX_EHDR, "invalid DSD chunk size"); + return SOX_EHDR; + } + + lsx_readqw(ft, &dsf->file_size); + lsx_readqw(ft, &dsf->metadata); + + if (lsx_readdw(ft, &magic) || magic != FMT_TAG) { + lsx_fail_errno(ft, SOX_EHDR, "fmt chunk not found"); + return SOX_EHDR; + } + + if (lsx_readqw(ft, &csize) || csize != 52) { + lsx_fail_errno(ft, SOX_EHDR, "invalid fmt chunk size"); + return SOX_EHDR; + } + + if (lsx_readdw(ft, &dsf->version) || + lsx_readdw(ft, &dsf->format_id) || + lsx_readdw(ft, &dsf->chan_type) || + lsx_readdw(ft, &dsf->chan_num) || + lsx_readdw(ft, &dsf->sfreq) || + lsx_readdw(ft, &dsf->bps) || + lsx_readqw(ft, &dsf->scount) || + lsx_readdw(ft, &dsf->block_size)) + return SOX_EHDR; + + if (lsx_readdw(ft, &v) || v) /* reserved */ + return SOX_EHDR; + + if (lsx_readdw(ft, &magic) || magic != DATA_TAG) { + lsx_fail_errno(ft, SOX_EHDR, "data chunk not found"); + return SOX_EHDR; + } + + if (lsx_readqw(ft, &csize) || + csize < 12 + dsf->block_size * dsf->chan_num) { + lsx_fail_errno(ft, SOX_EHDR, "invalid data chunk size"); + return SOX_EHDR; + } + + if (dsf->version != 1) { + lsx_fail_errno(ft, SOX_EHDR, "unknown format version %d", + dsf->version); + return SOX_EHDR; + } + + if (dsf->format_id != 0) { + lsx_fail_errno(ft, SOX_EFMT, "unknown format ID %d", + dsf->format_id); + return SOX_EFMT; + } + + if (dsf->chan_num < 1 || dsf->chan_num > 6) { + lsx_fail_errno(ft, SOX_EHDR, "inavlid channel count %d", + dsf->chan_num); + return SOX_EHDR; + } + + if (dsf->bps != 1) { + lsx_fail_errno(ft, SOX_EFMT, "unsupported bit depth %d", + dsf->bps); + return SOX_EFMT; + } + + dsf->block = lsx_calloc(dsf->chan_num, dsf->block_size); + if (!dsf->block) + return SOX_ENOMEM; + + dsf->block_pos = dsf->block_size; + + ft->signal.rate = dsf->sfreq; + ft->signal.channels = dsf->chan_num; + ft->signal.precision = 1; + ft->signal.length = dsf->scount * dsf->chan_num; + + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + ft->encoding.bits_per_sample = 1; + + return SOX_SUCCESS; +} + +static size_t dsf_read(sox_format_t *ft, sox_sample_t *buf, size_t len) +{ + struct dsf *dsf = ft->priv; + uint64_t samp_left = dsf->scount - dsf->read_samp; + size_t rsamp = 0; + uint8_t *dsd; + unsigned i, j; + + len /= dsf->chan_num; + len = min(len, samp_left); + + while (len >= 8) { + if (dsf->block_pos >= dsf->block_size) { + size_t rlen = dsf->chan_num * dsf->block_size; + if (lsx_read_b_buf(ft, dsf->block, rlen) < rlen) + return rsamp * dsf->chan_num; + dsf->block_pos = 0; + } + + dsd = dsf->block + dsf->block_pos; + + for (i = 0; i < dsf->chan_num; i++) { + unsigned d = dsd[i * dsf->block_size]; + + for (j = 0; j < 8; j++) { + buf[i + j * dsf->chan_num] = d & 1 ? + SOX_SAMPLE_MAX : -SOX_SAMPLE_MAX; + d >>= 1; + } + } + + buf += 8 * dsf->chan_num; + + dsf->block_pos++; + rsamp += 8; + len -= 8; + } + + return rsamp * dsf->chan_num; +} + +static int dsf_stopread(sox_format_t *ft) +{ + struct dsf *dsf = ft->priv; + + free(dsf->block); + + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(dsf) +{ + static char const * const names[] = { "dsf", NULL }; + static unsigned const write_encodings[] = { 0 }; + static sox_format_handler_t const handler = { + SOX_LIB_VERSION_CODE, + "Container for DSD data", + names, SOX_FILE_LIT_END, + dsf_startread, dsf_read, dsf_stopread, + NULL, NULL, NULL, + NULL, write_encodings, NULL, + sizeof(struct dsf) + }; + return &handler; +} diff --git a/src/formats.h b/src/formats.h index a42ce27..4701efd 100644 --- a/src/formats.h +++ b/src/formats.h @@ -26,6 +26,7 @@ FORMAT(cvsd) FORMAT(cvu) FORMAT(dat) + FORMAT(dsf) FORMAT(dvms) FORMAT(f4) FORMAT(f8) -- 2.5.0 ------------------------------------------------------------------------------