1 /* Psion Record format (format of sound files used for EPOC machines).
2  * The file normally has no extension, so SoX uses .prc (Psion ReCord).
3  * Based (heavily) on the wve.c format file.
4  * Hacked by Bert van Leeuwen (bert@e.co.za)
5  *
6  * Header check improved, ADPCM encoding added, and other improvements
7  * by Reuben Thomas <rrt@sc3d.org>, using file format info at
8  * http://software.frodo.looijaard.name/psiconv/formats/
9  *
10  * This library is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or (at
13  * your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this library; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  * Includes code for ADPCM framing based on code carrying the
25  * following copyright:
26  *
27  *******************************************************************
28  Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
29  Netherlands.
30 
31                         All Rights Reserved
32 
33  Permission to use, copy, modify, and distribute this software and its
34  documentation for any purpose and without fee is hereby granted,
35  provided that the above copyright notice appear in all copies and that
36  both that copyright notice and this permission notice appear in
37  supporting documentation, and that the names of Stichting Mathematisch
38  Centrum or CWI not be used in advertising or publicity pertaining to
39  distribution of the software without specific, written prior permission.
40 
41  STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
42  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43  FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
44  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
45  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
46  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
47  OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48  ******************************************************************/
49 
50 
51 #include "sox_i.h"
52 
53 #include "adpcms.h"
54 
55 #include <assert.h>
56 #include <string.h>
57 #include <errno.h>
58 #include <limits.h>
59 
60 typedef struct {
61   uint32_t nsamp, nbytes;
62   short padding;
63   short repeats;
64   off_t data_start;         /* for seeking */
65   adpcm_io_t adpcm;
66   unsigned frame_samp;     /* samples left to read in current frame */
67 } priv_t;
68 
69 static void prcwriteheader(sox_format_t * ft);
70 
71 static int seek(sox_format_t * ft, uint64_t offset)
72 {
73   priv_t * p = (priv_t *)ft->priv;
74   if (ft->encoding.encoding == SOX_ENCODING_ALAW)
75     return lsx_offset_seek(ft, (off_t)p->data_start, (off_t)offset);
76   return SOX_EOF;
77 }
78 
79 /* File header. The first 4 words are fixed; the rest of the header
80    could theoretically be different, and this is the first place to
81    check with apparently invalid files.
82 
83    N.B. All offsets are from start of file. */
84 static const char prc_header[41] = {
85   /* Header section */
86   '\x37','\x00','\x00','\x10', /* 0x00: File type (UID 1) */
87   '\x6d','\x00','\x00','\x10', /* 0x04: File kind (UID 2) */
88   '\x7e','\x00','\x00','\x10', /* 0x08: Application ID (UID 3) */
89   '\xcf','\xac','\x08','\x55', /* 0x0c: Checksum of UIDs 1-3 */
90   '\x14','\x00','\x00','\x00', /* 0x10: File offset of Section Table Section */
91   /* Section Table Section: a BListL, i.e. a list of longs preceded by
92      length byte.
93      The longs are in (ID, offset) pairs, each pair identifying a
94      section. */
95   '\x04',                      /* 0x14: List has 4 bytes, i.e. 2 pairs */
96   '\x52','\x00','\x00','\x10', /* 0x15: ID: Record Section */
97   '\x34','\x00','\x00','\x00', /* 0x19: Offset to Record Section */
98   '\x89','\x00','\x00','\x10', /* 0x1d: ID: Application ID Section */
99   '\x25','\x00','\x00','\x00', /* 0x21: Offset to Application ID Section */
100   '\x7e','\x00','\x00','\x10', /* 0x25: Application ID Section:
101                                   Record.app identifier */
102   /* Next comes the string, which can be either case. */
103 };
104 
105 /* Format of the Record Section (offset 0x34):
106 
107 00 L Uncompressed data length
108 04 ID a1 01 00 10 for ADPCM, 00 00 00 00 for A-law
109 08 W number of times sound will be repeated (0 = played once)
110 0a B Volume setting (01-05)
111 0b B Always 00 (?)
112 0c L Time between repeats in usec
113 10 LListB (i.e. long giving number of bytes followed by bytes) Sound Data
114 */
115 
116 static int prc_checkheader(sox_format_t * ft, char *head)
117 {
118   lsx_readbuf(ft, head, sizeof(prc_header));
119   return memcmp(head, prc_header, sizeof(prc_header)) == 0;
120 }
121 
122 static int startread(sox_format_t * ft)
123 {
124   priv_t * p = (priv_t *)ft->priv;
125   char head[sizeof(prc_header)];
126   uint8_t byte;
127   uint16_t reps;
128   uint32_t len, listlen, encoding, repgap;
129   unsigned char volume;
130   char appname[0x40]; /* Maximum possible length of name */
131 
132   /* Check the header */
133   if (prc_checkheader(ft, head))
134     lsx_debug("Found Psion Record header");
135   else {
136       lsx_fail_errno(ft,SOX_EHDR,"Not a Psion Record file");
137       return (SOX_EOF);
138   }
139 
140   lsx_readb(ft, &byte);
141   if ((byte & 0x3) != 0x2) {
142     lsx_fail_errno(ft, SOX_EHDR, "Invalid length byte for application name string %d", (int)(byte));
143     return SOX_EOF;
144   }
145 
146   byte >>= 2;
147   assert(byte < 64);
148   lsx_reads(ft, appname, (size_t)byte);
149   if (strncasecmp(appname, "record.app", (size_t) byte) != 0) {
150     lsx_fail_errno(ft, SOX_EHDR, "Invalid application name string %.63s", appname);
151     return SOX_EOF;
152   }
153 
154   lsx_readdw(ft, &len);
155   p->nsamp = len;
156   lsx_debug("Number of samples: %d", len);
157 
158   lsx_readdw(ft, &encoding);
159   lsx_debug("Encoding of samples: %x", encoding);
160   if (encoding == 0)
161     ft->encoding.encoding = SOX_ENCODING_ALAW;
162   else if (encoding == 0x100001a1)
163     ft->encoding.encoding = SOX_ENCODING_IMA_ADPCM;
164   else {
165     lsx_fail_errno(ft, SOX_EHDR, "Unrecognised encoding");
166     return SOX_EOF;
167   }
168 
169   lsx_readw(ft, &reps);    /* Number of repeats */
170   lsx_debug("Repeats: %d", reps);
171 
172   lsx_readb(ft, &volume);
173   lsx_debug("Volume: %d", (unsigned)volume);
174   if (volume < 1 || volume > 5)
175     lsx_warn("Volume %d outside range 1..5", volume);
176 
177   lsx_readb(ft, &byte);   /* Unused and seems always zero */
178 
179   lsx_readdw(ft, &repgap); /* Time between repeats in usec */
180   lsx_debug("Time between repeats (usec): %u", repgap);
181 
182   lsx_readdw(ft, &listlen); /* Length of samples list */
183   lsx_debug("Number of bytes in samples list: %u", listlen);
184 
185   if (ft->signal.rate != 0 && ft->signal.rate != 8000)
186     lsx_report("PRC only supports 8 kHz; overriding.");
187   ft->signal.rate = 8000;
188 
189   if (ft->signal.channels != 1 && ft->signal.channels != 0)
190     lsx_report("PRC only supports 1 channel; overriding.");
191   ft->signal.channels = 1;
192 
193   p->data_start = lsx_tell(ft);
194   ft->signal.length = p->nsamp / ft->signal.channels;
195 
196   if (ft->encoding.encoding == SOX_ENCODING_ALAW) {
197     ft->encoding.bits_per_sample = 8;
198     if (lsx_rawstartread(ft))
199       return SOX_EOF;
200   } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
201     p->frame_samp = 0;
202     if (lsx_adpcm_ima_start(ft, &p->adpcm))
203       return SOX_EOF;
204   }
205 
206   return (SOX_SUCCESS);
207 }
208 
209 /* Read a variable-length encoded count */
210 /* Ignore return code of lsx_readb, as it doesn't really matter if EOF
211    is delayed until the caller. */
212 static unsigned read_cardinal(sox_format_t * ft)
213 {
214   unsigned a;
215   uint8_t byte;
216 
217   if (lsx_readb(ft, &byte) == SOX_EOF)
218     return (unsigned)SOX_EOF;
219   lsx_debug_more("Cardinal byte 1: %x", byte);
220   a = byte;
221   if (!(a & 1))
222     a >>= 1;
223   else {
224     if (lsx_readb(ft, &byte) == SOX_EOF)
225       return (unsigned)SOX_EOF;
226     lsx_debug_more("Cardinal byte 2: %x", byte);
227     a |= byte << 8;
228     if (!(a & 2))
229       a >>= 2;
230     else if (!(a & 4)) {
231       if (lsx_readb(ft, &byte) == SOX_EOF)
232         return (unsigned)SOX_EOF;
233       lsx_debug_more("Cardinal byte 3: %x", byte);
234       a |= byte << 16;
235       if (lsx_readb(ft, &byte) == SOX_EOF)
236         return (unsigned)SOX_EOF;
237       lsx_debug_more("Cardinal byte 4: %x", byte);
238       a |= byte << 24;
239       a >>= 3;
240     }
241   }
242 
243   return a;
244 }
245 
246 static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t samp)
247 {
248   priv_t * p = (priv_t *)ft->priv;
249 
250   lsx_debug_more("length now = %d", p->nsamp);
251 
252   if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
253     size_t nsamp, read;
254 
255     if (p->frame_samp == 0) {
256       unsigned framelen = read_cardinal(ft);
257       uint32_t trash;
258 
259       if (framelen == (unsigned)SOX_EOF)
260         return 0;
261 
262       lsx_debug_more("frame length %d", framelen);
263       p->frame_samp = framelen;
264 
265       /* Discard length of compressed data */
266       lsx_debug_more("compressed length %d", read_cardinal(ft));
267       /* Discard length of BListL */
268       lsx_readdw(ft, &trash);
269       lsx_debug_more("list length %d", trash);
270 
271       /* Reset CODEC for start of frame */
272       lsx_adpcm_reset(&p->adpcm, ft->encoding.encoding);
273     }
274     nsamp = min(p->frame_samp, samp);
275     p->nsamp += nsamp;
276     read = lsx_adpcm_read(ft, &p->adpcm, buf, nsamp);
277     p->frame_samp -= read;
278     lsx_debug_more("samples left in this frame: %d", p->frame_samp);
279     return read;
280   } else {
281     p->nsamp += samp;
282     return lsx_rawread(ft, buf, samp);
283   }
284 }
285 
286 static int stopread(sox_format_t * ft)
287 {
288   priv_t * p = (priv_t *)ft->priv;
289 
290   if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM)
291     return lsx_adpcm_stopread(ft, &p->adpcm);
292   else
293     return SOX_SUCCESS;
294 }
295 
296 /* When writing, the header is supposed to contain the number of
297    data bytes written, unless it is written to a pipe.
298    Since we don't know how many bytes will follow until we're done,
299    we first write the header with an unspecified number of bytes,
300    and at the end we rewind the file and write the header again
301    with the right size.  This only works if the file is seekable;
302    if it is not, the unspecified size remains in the header
303    (this is illegal). */
304 
305 static int startwrite(sox_format_t * ft)
306 {
307   priv_t * p = (priv_t *)ft->priv;
308 
309   if (ft->encoding.encoding == SOX_ENCODING_ALAW) {
310     if (lsx_rawstartwrite(ft))
311       return SOX_EOF;
312   } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
313     if (lsx_adpcm_ima_start(ft, &p->adpcm))
314       return SOX_EOF;
315   }
316 
317   p->nsamp = 0;
318   p->nbytes = 0;
319   if (p->repeats == 0)
320     p->repeats = 1;
321 
322   prcwriteheader(ft);
323 
324   p->data_start = lsx_tell(ft);
325 
326   return SOX_SUCCESS;
327 }
328 
329 static void write_cardinal(sox_format_t * ft, unsigned a)
330 {
331   uint8_t byte;
332 
333   if (a < 0x80) {
334     byte = a << 1;
335     lsx_debug_more("Cardinal byte 1: %x", byte);
336     lsx_writeb(ft, byte);
337   } else if (a < 0x8000) {
338     byte = (a << 2) | 1;
339     lsx_debug_more("Cardinal byte 1: %x", byte);
340     lsx_writeb(ft, byte);
341     byte = a >> 6;
342     lsx_debug_more("Cardinal byte 2: %x", byte);
343     lsx_writeb(ft, byte);
344   } else {
345     byte = (a << 3) | 3;
346     lsx_debug_more("Cardinal byte 1: %x", byte);
347     lsx_writeb(ft, byte);
348     byte = a >> 5;
349     lsx_debug_more("Cardinal byte 2: %x", byte);
350     lsx_writeb(ft, byte);
351     byte = a >> 13;
352     lsx_debug_more("Cardinal byte 3: %x", byte);
353     lsx_writeb(ft, byte);
354     byte = a >> 21;
355     lsx_debug_more("Cardinal byte 4: %x", byte);
356     lsx_writeb(ft, byte);
357   }
358 }
359 
360 static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp)
361 {
362   priv_t * p = (priv_t *)ft->priv;
363   /* Psion Record seems not to be able to handle frames > 800 samples */
364   size_t written = 0;
365   lsx_debug_more("length now = %d", p->nsamp);
366   if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
367     while (written < nsamp) {
368       size_t written1, samp = min(nsamp - written, 800);
369 
370       write_cardinal(ft, (unsigned) samp);
371       /* Write compressed length */
372       write_cardinal(ft, (unsigned) ((samp / 2) + (samp % 2) + 4));
373       /* Write length again (seems to be a BListL) */
374       lsx_debug_more("list length %lu", (unsigned long)samp);
375       lsx_writedw(ft, (unsigned) samp);
376       lsx_adpcm_reset(&p->adpcm, ft->encoding.encoding);
377       written1 = lsx_adpcm_write(ft, &p->adpcm, buf + written, samp);
378       if (written1 != samp)
379         break;
380       lsx_adpcm_flush(ft, &p->adpcm);
381       written += written1;
382     }
383   } else
384     written = lsx_rawwrite(ft, buf, nsamp);
385   p->nsamp += written;
386   return written;
387 }
388 
389 static int stopwrite(sox_format_t * ft)
390 {
391   priv_t * p = (priv_t *)ft->priv;
392 
393   p->nbytes = lsx_tell(ft) - p->data_start;
394 
395   if (!ft->seekable) {
396       lsx_warn("Header will have invalid file length since file is not seekable");
397       return SOX_SUCCESS;
398   }
399 
400   if (lsx_seeki(ft, (off_t)0, 0) != 0) {
401       lsx_fail_errno(ft,errno,"Can't rewind output file to rewrite Psion header.");
402       return(SOX_EOF);
403   }
404   prcwriteheader(ft);
405   return SOX_SUCCESS;
406 }
407 
408 static void prcwriteheader(sox_format_t * ft)
409 {
410   priv_t * p = (priv_t *)ft->priv;
411 
412   lsx_writebuf(ft, prc_header, sizeof(prc_header));
413   lsx_writes(ft, "\x2arecord.app");
414 
415   lsx_debug("Number of samples: %d",p->nsamp);
416   lsx_writedw(ft, p->nsamp);
417 
418   if (ft->encoding.encoding == SOX_ENCODING_ALAW)
419     lsx_writedw(ft, 0);
420   else
421     lsx_writedw(ft, 0x100001a1); /* ADPCM */
422 
423   lsx_writew(ft, 0);             /* Number of repeats */
424   lsx_writeb(ft, 3);             /* Volume: use default value of Record.app */
425   lsx_writeb(ft, 0);             /* Unused and seems always zero */
426   lsx_writedw(ft, 0);            /* Time between repeats in usec */
427 
428   lsx_debug("Number of bytes: %d", p->nbytes);
429   lsx_writedw(ft, p->nbytes);    /* Number of bytes of data */
430 }
431 
432 LSX_FORMAT_HANDLER(prc)
433 {
434   static char const * const names[]           = {"prc", NULL};
435   static sox_rate_t   const write_rates[]     = {8000, 0};
436   static unsigned     const write_encodings[] = {
437     SOX_ENCODING_ALAW, 8, 0,
438     SOX_ENCODING_IMA_ADPCM, 4, 0,
439     0};
440   static sox_format_handler_t const handler = {
441     SOX_LIB_VERSION_CODE,
442     "Psion Record; used in EPOC devices (Series 5, Revo and similar)",
443     names, SOX_FILE_LIT_END | SOX_FILE_MONO,
444     startread, read_samples, stopread,
445     startwrite, write_samples, stopwrite,
446     seek, write_encodings, write_rates, sizeof(priv_t)
447   };
448   return &handler;
449 }
450