diff --git a/app/src/main/cpp/sox/CmakeLists.txt b/app/src/main/cpp/sox/CmakeLists.txt index da4b6e9..65f715f 100644 --- a/app/src/main/cpp/sox/CmakeLists.txt +++ b/app/src/main/cpp/sox/CmakeLists.txt @@ -102,7 +102,6 @@ set(formats_srcs ima_rw.c la-fmt.c lu-fmt.c - prc.c raw.c raw.h raw-fmt.c diff --git a/app/src/main/cpp/sox/formats.h b/app/src/main/cpp/sox/formats.h index ae83afd..f516572 100644 --- a/app/src/main/cpp/sox/formats.h +++ b/app/src/main/cpp/sox/formats.h @@ -37,7 +37,7 @@ FORMAT(lu) // FORMAT(maud) // FORMAT(nul) - FORMAT(prc) +// FORMAT(prc) FORMAT(raw) FORMAT(s1) FORMAT(s2) diff --git a/app/src/main/cpp/sox/prc.c b/app/src/main/cpp/sox/prc.c deleted file mode 100644 index 58f765e..0000000 --- a/app/src/main/cpp/sox/prc.c +++ /dev/null @@ -1,449 +0,0 @@ -/* Psion Record format (format of sound files used for EPOC machines). - * The file normally has no extension, so SoX uses .prc (Psion ReCord). - * Based (heavily) on the wve.c format file. - * Hacked by Bert van Leeuwen (bert@e.co.za) - * - * Header check improved, ADPCM encoding added, and other improvements - * by Reuben Thomas , using file format info at - * http://software.frodo.looijaard.name/psiconv/formats/ - * - * 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 - * - * Includes code for ADPCM framing based on code carrying the - * following copyright: - * - ******************************************************************* - Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The - Netherlands. - - All Rights Reserved - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose and without fee is hereby granted, - provided that the above copyright notice appear in all copies and that - both that copyright notice and this permission notice appear in - supporting documentation, and that the names of Stichting Mathematisch - Centrum or CWI not be used in advertising or publicity pertaining to - distribution of the software without specific, written prior permission. - - STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO - THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE - FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ******************************************************************/ - - -#include "sox_i.h" - -#include "adpcms.h" - -#include -#include -#include -#include - -typedef struct { - uint32_t nsamp, nbytes; - short padding; - short repeats; - off_t data_start; /* for seeking */ - adpcm_io_t adpcm; - unsigned frame_samp; /* samples left to read in current frame */ -} priv_t; - -static void prcwriteheader(sox_format_t * ft); - -static int seek(sox_format_t * ft, uint64_t offset) -{ - priv_t * p = (priv_t *)ft->priv; - if (ft->encoding.encoding == SOX_ENCODING_ALAW) - return lsx_offset_seek(ft, (off_t)p->data_start, (off_t)offset); - return SOX_EOF; -} - -/* File header. The first 4 words are fixed; the rest of the header - could theoretically be different, and this is the first place to - check with apparently invalid files. - - N.B. All offsets are from start of file. */ -static const char prc_header[41] = { - /* Header section */ - '\x37','\x00','\x00','\x10', /* 0x00: File type (UID 1) */ - '\x6d','\x00','\x00','\x10', /* 0x04: File kind (UID 2) */ - '\x7e','\x00','\x00','\x10', /* 0x08: Application ID (UID 3) */ - '\xcf','\xac','\x08','\x55', /* 0x0c: Checksum of UIDs 1-3 */ - '\x14','\x00','\x00','\x00', /* 0x10: File offset of Section Table Section */ - /* Section Table Section: a BListL, i.e. a list of longs preceded by - length byte. - The longs are in (ID, offset) pairs, each pair identifying a - section. */ - '\x04', /* 0x14: List has 4 bytes, i.e. 2 pairs */ - '\x52','\x00','\x00','\x10', /* 0x15: ID: Record Section */ - '\x34','\x00','\x00','\x00', /* 0x19: Offset to Record Section */ - '\x89','\x00','\x00','\x10', /* 0x1d: ID: Application ID Section */ - '\x25','\x00','\x00','\x00', /* 0x21: Offset to Application ID Section */ - '\x7e','\x00','\x00','\x10', /* 0x25: Application ID Section: - Record.app identifier */ - /* Next comes the string, which can be either case. */ -}; - -/* Format of the Record Section (offset 0x34): - -00 L Uncompressed data length -04 ID a1 01 00 10 for ADPCM, 00 00 00 00 for A-law -08 W number of times sound will be repeated (0 = played once) -0a B Volume setting (01-05) -0b B Always 00 (?) -0c L Time between repeats in usec -10 LListB (i.e. long giving number of bytes followed by bytes) Sound Data -*/ - -static int prc_checkheader(sox_format_t * ft, char *head) -{ - lsx_readbuf(ft, head, sizeof(prc_header)); - return memcmp(head, prc_header, sizeof(prc_header)) == 0; -} - -static int startread(sox_format_t * ft) -{ - priv_t * p = (priv_t *)ft->priv; - char head[sizeof(prc_header)]; - uint8_t byte; - uint16_t reps; - uint32_t len, listlen, encoding, repgap; - unsigned char volume; - char appname[0x40]; /* Maximum possible length of name */ - - /* Check the header */ - if (prc_checkheader(ft, head)) - lsx_debug("Found Psion Record header"); - else { - lsx_fail_errno(ft,SOX_EHDR,"Not a Psion Record file"); - return (SOX_EOF); - } - - lsx_readb(ft, &byte); - if ((byte & 0x3) != 0x2) { - lsx_fail_errno(ft, SOX_EHDR, "Invalid length byte for application name string %d", (int)(byte)); - return SOX_EOF; - } - - byte >>= 2; - assert(byte < 64); - lsx_reads(ft, appname, (size_t)byte); - if (strncasecmp(appname, "record.app", (size_t) byte) != 0) { - lsx_fail_errno(ft, SOX_EHDR, "Invalid application name string %.63s", appname); - return SOX_EOF; - } - - lsx_readdw(ft, &len); - p->nsamp = len; - lsx_debug("Number of samples: %d", len); - - lsx_readdw(ft, &encoding); - lsx_debug("Encoding of samples: %x", encoding); - if (encoding == 0) - ft->encoding.encoding = SOX_ENCODING_ALAW; - else if (encoding == 0x100001a1) - ft->encoding.encoding = SOX_ENCODING_IMA_ADPCM; - else { - lsx_fail_errno(ft, SOX_EHDR, "Unrecognised encoding"); - return SOX_EOF; - } - - lsx_readw(ft, &reps); /* Number of repeats */ - lsx_debug("Repeats: %d", reps); - - lsx_readb(ft, &volume); - lsx_debug("Volume: %d", (unsigned)volume); - if (volume < 1 || volume > 5) - lsx_warn("Volume %d outside range 1..5", volume); - - lsx_readb(ft, &byte); /* Unused and seems always zero */ - - lsx_readdw(ft, &repgap); /* Time between repeats in usec */ - lsx_debug("Time between repeats (usec): %u", repgap); - - lsx_readdw(ft, &listlen); /* Length of samples list */ - lsx_debug("Number of bytes in samples list: %u", listlen); - - if (ft->signal.rate != 0 && ft->signal.rate != 8000) - lsx_report("PRC only supports 8 kHz; overriding."); - ft->signal.rate = 8000; - - if (ft->signal.channels != 1 && ft->signal.channels != 0) - lsx_report("PRC only supports 1 channel; overriding."); - ft->signal.channels = 1; - - p->data_start = lsx_tell(ft); - ft->signal.length = p->nsamp / ft->signal.channels; - - if (ft->encoding.encoding == SOX_ENCODING_ALAW) { - ft->encoding.bits_per_sample = 8; - if (lsx_rawstartread(ft)) - return SOX_EOF; - } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { - p->frame_samp = 0; - if (lsx_adpcm_ima_start(ft, &p->adpcm)) - return SOX_EOF; - } - - return (SOX_SUCCESS); -} - -/* Read a variable-length encoded count */ -/* Ignore return code of lsx_readb, as it doesn't really matter if EOF - is delayed until the caller. */ -static unsigned read_cardinal(sox_format_t * ft) -{ - unsigned a; - uint8_t byte; - - if (lsx_readb(ft, &byte) == SOX_EOF) - return (unsigned)SOX_EOF; - lsx_debug_more("Cardinal byte 1: %x", byte); - a = byte; - if (!(a & 1)) - a >>= 1; - else { - if (lsx_readb(ft, &byte) == SOX_EOF) - return (unsigned)SOX_EOF; - lsx_debug_more("Cardinal byte 2: %x", byte); - a |= byte << 8; - if (!(a & 2)) - a >>= 2; - else if (!(a & 4)) { - if (lsx_readb(ft, &byte) == SOX_EOF) - return (unsigned)SOX_EOF; - lsx_debug_more("Cardinal byte 3: %x", byte); - a |= byte << 16; - if (lsx_readb(ft, &byte) == SOX_EOF) - return (unsigned)SOX_EOF; - lsx_debug_more("Cardinal byte 4: %x", byte); - a |= byte << 24; - a >>= 3; - } - } - - return a; -} - -static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t samp) -{ - priv_t * p = (priv_t *)ft->priv; - - lsx_debug_more("length now = %d", p->nsamp); - - if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { - size_t nsamp, read; - - if (p->frame_samp == 0) { - unsigned framelen = read_cardinal(ft); - uint32_t trash; - - if (framelen == (unsigned)SOX_EOF) - return 0; - - lsx_debug_more("frame length %d", framelen); - p->frame_samp = framelen; - - /* Discard length of compressed data */ - lsx_debug_more("compressed length %d", read_cardinal(ft)); - /* Discard length of BListL */ - lsx_readdw(ft, &trash); - lsx_debug_more("list length %d", trash); - - /* Reset CODEC for start of frame */ - lsx_adpcm_reset(&p->adpcm, ft->encoding.encoding); - } - nsamp = min(p->frame_samp, samp); - p->nsamp += nsamp; - read = lsx_adpcm_read(ft, &p->adpcm, buf, nsamp); - p->frame_samp -= read; - lsx_debug_more("samples left in this frame: %d", p->frame_samp); - return read; - } else { - p->nsamp += samp; - return lsx_rawread(ft, buf, samp); - } -} - -static int stopread(sox_format_t * ft) -{ - priv_t * p = (priv_t *)ft->priv; - - if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) - return lsx_adpcm_stopread(ft, &p->adpcm); - else - return SOX_SUCCESS; -} - -/* When writing, the header is supposed to contain the number of - data bytes written, unless it is written to a pipe. - Since we don't know how many bytes will follow until we're done, - we first write the header with an unspecified number of bytes, - and at the end we rewind the file and write the header again - with the right size. This only works if the file is seekable; - if it is not, the unspecified size remains in the header - (this is illegal). */ - -static int startwrite(sox_format_t * ft) -{ - priv_t * p = (priv_t *)ft->priv; - - if (ft->encoding.encoding == SOX_ENCODING_ALAW) { - if (lsx_rawstartwrite(ft)) - return SOX_EOF; - } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { - if (lsx_adpcm_ima_start(ft, &p->adpcm)) - return SOX_EOF; - } - - p->nsamp = 0; - p->nbytes = 0; - if (p->repeats == 0) - p->repeats = 1; - - prcwriteheader(ft); - - p->data_start = lsx_tell(ft); - - return SOX_SUCCESS; -} - -static void write_cardinal(sox_format_t * ft, unsigned a) -{ - uint8_t byte; - - if (a < 0x80) { - byte = a << 1; - lsx_debug_more("Cardinal byte 1: %x", byte); - lsx_writeb(ft, byte); - } else if (a < 0x8000) { - byte = (a << 2) | 1; - lsx_debug_more("Cardinal byte 1: %x", byte); - lsx_writeb(ft, byte); - byte = a >> 6; - lsx_debug_more("Cardinal byte 2: %x", byte); - lsx_writeb(ft, byte); - } else { - byte = (a << 3) | 3; - lsx_debug_more("Cardinal byte 1: %x", byte); - lsx_writeb(ft, byte); - byte = a >> 5; - lsx_debug_more("Cardinal byte 2: %x", byte); - lsx_writeb(ft, byte); - byte = a >> 13; - lsx_debug_more("Cardinal byte 3: %x", byte); - lsx_writeb(ft, byte); - byte = a >> 21; - lsx_debug_more("Cardinal byte 4: %x", byte); - lsx_writeb(ft, byte); - } -} - -static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp) -{ - priv_t * p = (priv_t *)ft->priv; - /* Psion Record seems not to be able to handle frames > 800 samples */ - size_t written = 0; - lsx_debug_more("length now = %d", p->nsamp); - if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { - while (written < nsamp) { - size_t written1, samp = min(nsamp - written, 800); - - write_cardinal(ft, (unsigned) samp); - /* Write compressed length */ - write_cardinal(ft, (unsigned) ((samp / 2) + (samp % 2) + 4)); - /* Write length again (seems to be a BListL) */ - lsx_debug_more("list length %lu", (unsigned long)samp); - lsx_writedw(ft, (unsigned) samp); - lsx_adpcm_reset(&p->adpcm, ft->encoding.encoding); - written1 = lsx_adpcm_write(ft, &p->adpcm, buf + written, samp); - if (written1 != samp) - break; - lsx_adpcm_flush(ft, &p->adpcm); - written += written1; - } - } else - written = lsx_rawwrite(ft, buf, nsamp); - p->nsamp += written; - return written; -} - -static int stopwrite(sox_format_t * ft) -{ - priv_t * p = (priv_t *)ft->priv; - - p->nbytes = lsx_tell(ft) - p->data_start; - - if (!ft->seekable) { - lsx_warn("Header will have invalid file length since file is not seekable"); - return SOX_SUCCESS; - } - - if (lsx_seeki(ft, (off_t)0, 0) != 0) { - lsx_fail_errno(ft,errno,"Can't rewind output file to rewrite Psion header."); - return(SOX_EOF); - } - prcwriteheader(ft); - return SOX_SUCCESS; -} - -static void prcwriteheader(sox_format_t * ft) -{ - priv_t * p = (priv_t *)ft->priv; - - lsx_writebuf(ft, prc_header, sizeof(prc_header)); - lsx_writes(ft, "\x2arecord.app"); - - lsx_debug("Number of samples: %d",p->nsamp); - lsx_writedw(ft, p->nsamp); - - if (ft->encoding.encoding == SOX_ENCODING_ALAW) - lsx_writedw(ft, 0); - else - lsx_writedw(ft, 0x100001a1); /* ADPCM */ - - lsx_writew(ft, 0); /* Number of repeats */ - lsx_writeb(ft, 3); /* Volume: use default value of Record.app */ - lsx_writeb(ft, 0); /* Unused and seems always zero */ - lsx_writedw(ft, 0); /* Time between repeats in usec */ - - lsx_debug("Number of bytes: %d", p->nbytes); - lsx_writedw(ft, p->nbytes); /* Number of bytes of data */ -} - -LSX_FORMAT_HANDLER(prc) -{ - static char const * const names[] = {"prc", NULL}; - static sox_rate_t const write_rates[] = {8000, 0}; - static unsigned const write_encodings[] = { - SOX_ENCODING_ALAW, 8, 0, - SOX_ENCODING_IMA_ADPCM, 4, 0, - 0}; - static sox_format_handler_t const handler = { - SOX_LIB_VERSION_CODE, - "Psion Record; used in EPOC devices (Series 5, Revo and similar)", - names, SOX_FILE_LIT_END | SOX_FILE_MONO, - startread, read_samples, stopread, - startwrite, write_samples, stopwrite, - seek, write_encodings, write_rates, sizeof(priv_t) - }; - return &handler; -}