1 /*      libSoX CVSD (Continuously Variable Slope Delta modulation)
2  *      conversion routines
3  *
4  *      The CVSD format is described in the MIL Std 188 113, which is
5  *      available from http://bbs.itsi.disa.mil:5580/T3564
6  *
7  *      Copyright (C) 1996
8  *      Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA)
9  *      Swiss Federal Institute of Technology, Electronics Lab
10  *
11  * This library is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or (at
14  * your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this library; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  * Change History:
26  *
27  * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com)
28  *   Fixed compile warnings reported by Kjetil Torgrim Homme
29  *   <kjetilho@ifi.uio.no>
30  *
31  * June 20, 2006 - Kimberly Rockwell (pyxis13317 (at) yahoo.com)
32  *   Speed optimization: Unrolled float_conv() loop in seperate
33  *     functions for encoding and decoding.  15% speed up decoding.
34  *
35  * Aug. 24, 2009 - P. Chaintreuil (sox-cvsd-peep (at) parallaxshift.com)
36  *   Speed optimization: Replaced calls to memmove() with a
37  *     mirrored circular buffer.  This doubles the size of the
38  *     dec.output_filter (48 -> 96 floats) and enc.input_filter
39  *     (16 -> 32 floats), but keeps the memory from having to
40  *     be copied so many times.  56% speed increase decoding;
41  *     less than 5% encoding speed increase.
42  */
43 
44 #include "sox_i.h"
45 #include "cvsd.h"
46 #include "cvsdfilt.h"
47 
48 #include <string.h>
49 #include <time.h>
50 
51 /* ---------------------------------------------------------------------- */
52 /*
53  * private data structures
54  */
55 
56 typedef cvsd_priv_t priv_t;
57 
58 static int debug_count = 0;
59 
60 /* ---------------------------------------------------------------------- */
61 
62 /* This float_conv() function is not used as more specialized/optimized
63  * versions exist below.  However, those new versions are tied to
64  * very percise filters defined in cvsdfilt.h.  If those are modified
65  * or different filters are found to be required, this function may
66  * be needed.  Thus I leave it here for possible future use, but commented
67  * out to avoid compiler warnings about it not being used.
68 static float float_conv(float const *fp1, float const *fp2,int n)
69 {
70         float res = 0;
71         for(; n > 0; n--)
72                 res += (*fp1++) * (*fp2++);
73         return res;
74 }
75 */
76 
float_conv_enc(float const * fp1,float const * fp2)77 static float float_conv_enc(float const *fp1, float const *fp2)
78 {
79     /* This is a specialzed version of float_conv() for encoding
80      * which simply assumes a CVSD_ENC_FILTERLEN (16) length of
81      * the two arrays and unrolls that loop.
82      *
83      * fp1 should be the enc.input_filter array and must be
84      * CVSD_ENC_FILTERLEN (16) long.
85      *
86      * fp2 should be one of the enc_filter_xx_y() tables listed
87      * in cvsdfilt.h.  At minimum, fp2 must be CVSD_ENC_FILTERLEN
88      * (16) entries long.
89      */
90     float res = 0;
91 
92     /* unrolling loop */
93     res += fp1[0] * fp2[0];
94     res += fp1[1] * fp2[1];
95     res += fp1[2] * fp2[2];
96     res += fp1[3] * fp2[3];
97     res += fp1[4] * fp2[4];
98     res += fp1[5] * fp2[5];
99     res += fp1[6] * fp2[6];
100     res += fp1[7] * fp2[7];
101     res += fp1[8] * fp2[8];
102     res += fp1[9] * fp2[9];
103     res += fp1[10] * fp2[10];
104     res += fp1[11] * fp2[11];
105     res += fp1[12] * fp2[12];
106     res += fp1[13] * fp2[13];
107     res += fp1[14] * fp2[14];
108     res += fp1[15] * fp2[15];
109 
110     return res;
111 }
112 
float_conv_dec(float const * fp1,float const * fp2)113 static float float_conv_dec(float const *fp1, float const *fp2)
114 {
115     /* This is a specialzed version of float_conv() for decoding
116      * which assumes a specific length and structure to the data
117      * in fp2.
118      *
119      * fp1 should be the dec.output_filter array and must be
120      * CVSD_DEC_FILTERLEN (48) long.
121      *
122      * fp2 should be one of the dec_filter_xx() tables listed
123      * in cvsdfilt.h.  fp2 is assumed to be CVSD_DEC_FILTERLEN
124      * (48) entries long, is assumed to have 0.0 in the last
125      * entry, and is a symmetrical mirror around fp2[23] (ie,
126      * fp2[22] == fp2[24], fp2[0] == fp2[47], etc).
127      */
128     float res = 0;
129 
130     /* unrolling loop, also taking advantage of the symmetry
131     * of the sampling rate array*/
132     res += (fp1[0] + fp1[46]) * fp2[0];
133     res += (fp1[1] + fp1[45]) * fp2[1];
134     res += (fp1[2] + fp1[44]) * fp2[2];
135     res += (fp1[3] + fp1[43]) * fp2[3];
136     res += (fp1[4] + fp1[42]) * fp2[4];
137     res += (fp1[5] + fp1[41]) * fp2[5];
138     res += (fp1[6] + fp1[40]) * fp2[6];
139     res += (fp1[7] + fp1[39]) * fp2[7];
140     res += (fp1[8] + fp1[38]) * fp2[8];
141     res += (fp1[9] + fp1[37]) * fp2[9];
142     res += (fp1[10] + fp1[36]) * fp2[10];
143     res += (fp1[11] + fp1[35]) * fp2[11];
144     res += (fp1[12] + fp1[34]) * fp2[12];
145     res += (fp1[13] + fp1[33]) * fp2[13];
146     res += (fp1[14] + fp1[32]) * fp2[14];
147     res += (fp1[15] + fp1[31]) * fp2[15];
148     res += (fp1[16] + fp1[30]) * fp2[16];
149     res += (fp1[17] + fp1[29]) * fp2[17];
150     res += (fp1[18] + fp1[28]) * fp2[18];
151     res += (fp1[19] + fp1[27]) * fp2[19];
152     res += (fp1[20] + fp1[26]) * fp2[20];
153     res += (fp1[21] + fp1[25]) * fp2[21];
154     res += (fp1[22] + fp1[24]) * fp2[22];
155     res += (fp1[23]) * fp2[23];
156 
157     return res;
158 }
159 
160 /* ---------------------------------------------------------------------- */
161 /*
162  * some remarks about the implementation of the CVSD decoder
163  * the principal integrator is integrated into the output filter
164  * to achieve this, the coefficients of the output filter are multiplied
165  * with (1/(1-1/z)) in the initialisation code.
166  * the output filter must have a sharp zero at f=0 (i.e. the sum of the
167  * filter parameters must be zero). This prevents an accumulation of
168  * DC voltage at the principal integration.
169  */
170 /* ---------------------------------------------------------------------- */
171 
cvsdstartcommon(sox_format_t * ft)172 static void cvsdstartcommon(sox_format_t * ft)
173 {
174         priv_t *p = (priv_t *) ft->priv;
175 
176         p->cvsd_rate = (ft->signal.rate <= 24000) ? 16000 : 32000;
177         ft->signal.rate = 8000;
178         ft->signal.channels = 1;
179         lsx_rawstart(ft, sox_true, sox_false, sox_true, SOX_ENCODING_CVSD, 1);
180         /*
181          * initialize the decoder
182          */
183         p->com.overload = 0x5;
184         p->com.mla_int = 0;
185         /*
186          * timeconst = (1/e)^(200 / SR) = exp(-200/SR)
187          * SR is the sampling rate
188          */
189         p->com.mla_tc0 = exp((-200.0)/((float)(p->cvsd_rate)));
190         /*
191          * phase_inc = 32000 / SR
192          */
193         p->com.phase_inc = 32000 / p->cvsd_rate;
194         /*
195          * initialize bit shift register
196          */
197         p->bit.shreg = p->bit.cnt = 0;
198         p->bit.mask = 1;
199         /*
200          * count the bytes written
201          */
202         p->bytes_written = 0;
203         p->com.v_min = 1;
204         p->com.v_max = -1;
205         lsx_report("cvsd: bit rate %dbit/s, bits from %s", p->cvsd_rate,
206                ft->encoding.reverse_bits ? "msb to lsb" : "lsb to msb");
207 }
208 
209 /* ---------------------------------------------------------------------- */
210 
lsx_cvsdstartread(sox_format_t * ft)211 int lsx_cvsdstartread(sox_format_t * ft)
212 {
213         priv_t *p = (priv_t *) ft->priv;
214         float *fp1;
215         int i;
216 
217         cvsdstartcommon(ft);
218 
219         p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0);
220         p->com.phase = 0;
221         /*
222          * initialize the output filter coeffs (i.e. multiply
223          * the coeffs with (1/(1-1/z)) to achieve integration
224          * this is now done in the filter parameter generation utility
225          */
226         /*
227          * zero the filter
228          */
229         for(fp1 = p->c.dec.output_filter, i = CVSD_DEC_FILTERLEN*2; i > 0; i--)
230                 *fp1++ = 0;
231         /* initialize mirror circular buffer offset to anything sane. */
232         p->c.dec.offset = CVSD_DEC_FILTERLEN - 1;
233 
234         return (SOX_SUCCESS);
235 }
236 
237 /* ---------------------------------------------------------------------- */
238 
lsx_cvsdstartwrite(sox_format_t * ft)239 int lsx_cvsdstartwrite(sox_format_t * ft)
240 {
241         priv_t *p = (priv_t *) ft->priv;
242         float *fp1;
243         int i;
244 
245         cvsdstartcommon(ft);
246 
247         p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0);
248         p->com.phase = 4;
249         /*
250          * zero the filter
251          */
252         for(fp1 = p->c.enc.input_filter, i = CVSD_ENC_FILTERLEN*2; i > 0; i--)
253                 *fp1++ = 0;
254         p->c.enc.recon_int = 0;
255         /* initialize mirror circular buffer offset to anything sane. */
256         p->c.enc.offset = CVSD_ENC_FILTERLEN - 1;
257 
258         return(SOX_SUCCESS);
259 }
260 
261 /* ---------------------------------------------------------------------- */
262 
lsx_cvsdstopwrite(sox_format_t * ft)263 int lsx_cvsdstopwrite(sox_format_t * ft)
264 {
265         priv_t *p = (priv_t *) ft->priv;
266 
267         if (p->bit.cnt) {
268                 lsx_writeb(ft, p->bit.shreg);
269                 p->bytes_written++;
270         }
271         lsx_debug("cvsd: min slope %f, max slope %f",
272                p->com.v_min, p->com.v_max);
273 
274         return (SOX_SUCCESS);
275 }
276 
277 /* ---------------------------------------------------------------------- */
278 
lsx_cvsdstopread(sox_format_t * ft)279 int lsx_cvsdstopread(sox_format_t * ft)
280 {
281         priv_t *p = (priv_t *) ft->priv;
282 
283         lsx_debug("cvsd: min value %f, max value %f",
284                p->com.v_min, p->com.v_max);
285 
286         return(SOX_SUCCESS);
287 }
288 
289 /* ---------------------------------------------------------------------- */
290 
lsx_cvsdread(sox_format_t * ft,sox_sample_t * buf,size_t nsamp)291 size_t lsx_cvsdread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp)
292 {
293         priv_t *p = (priv_t *) ft->priv;
294         size_t done = 0;
295         float oval;
296 
297         while (done < nsamp) {
298                 if (!p->bit.cnt) {
299                         if (lsx_read_b_buf(ft, &(p->bit.shreg), (size_t) 1) != 1)
300                                 return done;
301                         p->bit.cnt = 8;
302                         p->bit.mask = 1;
303                 }
304                 /*
305                  * handle one bit
306                  */
307                 p->bit.cnt--;
308                 p->com.overload = ((p->com.overload << 1) |
309                                    (!!(p->bit.shreg & p->bit.mask))) & 7;
310                 p->bit.mask <<= 1;
311                 p->com.mla_int *= p->com.mla_tc0;
312                 if ((p->com.overload == 0) || (p->com.overload == 7))
313                         p->com.mla_int += p->com.mla_tc1;
314 
315                 /* shift output filter window in mirror cirular buffer. */
316                 if (p->c.dec.offset != 0)
317                         --p->c.dec.offset;
318                 else p->c.dec.offset = CVSD_DEC_FILTERLEN - 1;
319                 /* write into both halves of the mirror circular buffer */
320                 if (p->com.overload & 1)
321                 {
322                         p->c.dec.output_filter[p->c.dec.offset] = p->com.mla_int;
323                         p->c.dec.output_filter[p->c.dec.offset + CVSD_DEC_FILTERLEN] = p->com.mla_int;
324                 }
325                 else
326                 {
327                         p->c.dec.output_filter[p->c.dec.offset] = -p->com.mla_int;
328                         p->c.dec.output_filter[p->c.dec.offset + CVSD_DEC_FILTERLEN] = -p->com.mla_int;
329                 }
330 
331                 /*
332                  * check if the next output is due
333                  */
334                 p->com.phase += p->com.phase_inc;
335                 if (p->com.phase >= 4) {
336                         oval = float_conv_dec(
337                                 p->c.dec.output_filter + p->c.dec.offset,
338                                 (p->cvsd_rate < 24000) ?
339                                 dec_filter_16 : dec_filter_32);
340                         lsx_debug_more("input %d %f\n", debug_count, p->com.mla_int);
341                         lsx_debug_more("recon %d %f\n", debug_count, oval);
342                         debug_count++;
343 
344                         if (oval > p->com.v_max)
345                                 p->com.v_max = oval;
346                         if (oval < p->com.v_min)
347                                 p->com.v_min = oval;
348                         *buf++ = (oval * ((float)SOX_SAMPLE_MAX));
349                         done++;
350                 }
351                 p->com.phase &= 3;
352         }
353         return done;
354 }
355 
356 /* ---------------------------------------------------------------------- */
357 
lsx_cvsdwrite(sox_format_t * ft,const sox_sample_t * buf,size_t nsamp)358 size_t lsx_cvsdwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp)
359 {
360         priv_t *p = (priv_t *) ft->priv;
361         size_t done = 0;
362         float inval;
363 
364         for(;;) {
365                 /*
366                  * check if the next input is due
367                  */
368                 if (p->com.phase >= 4) {
369                         if (done >= nsamp)
370                                 return done;
371 
372                         /* shift input filter window in mirror cirular buffer. */
373                         if (p->c.enc.offset != 0)
374                                 --p->c.enc.offset;
375                         else p->c.enc.offset = CVSD_ENC_FILTERLEN - 1;
376 
377                         /* write into both halves of the mirror circular buffer */
378                         p->c.enc.input_filter[p->c.enc.offset] =
379                                  p->c.enc.input_filter[p->c.enc.offset
380                                      + CVSD_ENC_FILTERLEN] =
381                                                 (*buf++) /
382                                                     ((float)SOX_SAMPLE_MAX);
383                         done++;
384                 }
385                 p->com.phase &= 3;
386                 /* insert input filter here! */
387                 inval = float_conv_enc(
388                                    p->c.enc.input_filter + p->c.enc.offset,
389                                    (p->cvsd_rate < 24000) ?
390                                    (enc_filter_16[(p->com.phase >= 2)]) :
391                                    (enc_filter_32[p->com.phase]));
392                 /*
393                  * encode one bit
394                  */
395                 p->com.overload = (((p->com.overload << 1) |
396                                     (inval >  p->c.enc.recon_int)) & 7);
397                 p->com.mla_int *= p->com.mla_tc0;
398                 if ((p->com.overload == 0) || (p->com.overload == 7))
399                         p->com.mla_int += p->com.mla_tc1;
400                 if (p->com.mla_int > p->com.v_max)
401                         p->com.v_max = p->com.mla_int;
402                 if (p->com.mla_int < p->com.v_min)
403                         p->com.v_min = p->com.mla_int;
404                 if (p->com.overload & 1) {
405                         p->c.enc.recon_int += p->com.mla_int;
406                         p->bit.shreg |= p->bit.mask;
407                 } else
408                         p->c.enc.recon_int -= p->com.mla_int;
409                 if ((++(p->bit.cnt)) >= 8) {
410                         lsx_writeb(ft, p->bit.shreg);
411                         p->bytes_written++;
412                         p->bit.shreg = p->bit.cnt = 0;
413                         p->bit.mask = 1;
414                 } else
415                         p->bit.mask <<= 1;
416                 p->com.phase += p->com.phase_inc;
417                 lsx_debug_more("input %d %f\n", debug_count, inval);
418                 lsx_debug_more("recon %d %f\n", debug_count, p->c.enc.recon_int);
419                 debug_count++;
420         }
421 }
422 
423 /* ---------------------------------------------------------------------- */
424 /*
425  * DVMS file header
426  */
427 
428 /* FIXME: eliminate these 4 functions */
429 
get32_le(unsigned char ** p)430 static uint32_t get32_le(unsigned char **p)
431 {
432   uint32_t val = (((*p)[3]) << 24) | (((*p)[2]) << 16) |
433           (((*p)[1]) << 8) | (**p);
434   (*p) += 4;
435   return val;
436 }
437 
get16_le(unsigned char ** p)438 static uint16_t get16_le(unsigned char **p)
439 {
440   unsigned val = (((*p)[1]) << 8) | (**p);
441   (*p) += 2;
442   return val;
443 }
444 
put32_le(unsigned char ** p,uint32_t val)445 static void put32_le(unsigned char **p, uint32_t val)
446 {
447   *(*p)++ = val & 0xff;
448   *(*p)++ = (val >> 8) & 0xff;
449   *(*p)++ = (val >> 16) & 0xff;
450   *(*p)++ = (val >> 24) & 0xff;
451 }
452 
put16_le(unsigned char ** p,unsigned val)453 static void put16_le(unsigned char **p, unsigned val)
454 {
455   *(*p)++ = val & 0xff;
456   *(*p)++ = (val >> 8) & 0xff;
457 }
458 
459 struct dvms_header {
460         char          Filename[14];
461         unsigned      Id;
462         unsigned      State;
463         time_t        Unixtime;
464         unsigned      Usender;
465         unsigned      Ureceiver;
466         size_t     Length;
467         unsigned      Srate;
468         unsigned      Days;
469         unsigned      Custom1;
470         unsigned      Custom2;
471         char          Info[16];
472         char          extend[64];
473         unsigned      Crc;
474 };
475 
476 #define DVMS_HEADER_LEN 120
477 
478 /* ---------------------------------------------------------------------- */
479 
dvms_read_header(sox_format_t * ft,struct dvms_header * hdr)480 static int dvms_read_header(sox_format_t * ft, struct dvms_header *hdr)
481 {
482         unsigned char hdrbuf[DVMS_HEADER_LEN];
483         unsigned char *pch = hdrbuf;
484         int i;
485         unsigned sum;
486 
487         if (lsx_readbuf(ft, hdrbuf, sizeof(hdrbuf)) != sizeof(hdrbuf))
488         {
489                 return (SOX_EOF);
490         }
491         for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
492                 sum += *pch++;
493         pch = hdrbuf;
494         memcpy(hdr->Filename, pch, sizeof(hdr->Filename));
495         pch += sizeof(hdr->Filename);
496         hdr->Id = get16_le(&pch);
497         hdr->State = get16_le(&pch);
498         hdr->Unixtime = get32_le(&pch);
499         hdr->Usender = get16_le(&pch);
500         hdr->Ureceiver = get16_le(&pch);
501         hdr->Length = get32_le(&pch);
502         hdr->Srate = get16_le(&pch);
503         hdr->Days = get16_le(&pch);
504         hdr->Custom1 = get16_le(&pch);
505         hdr->Custom2 = get16_le(&pch);
506         memcpy(hdr->Info, pch, sizeof(hdr->Info));
507         pch += sizeof(hdr->Info);
508         memcpy(hdr->extend, pch, sizeof(hdr->extend));
509         pch += sizeof(hdr->extend);
510         hdr->Crc = get16_le(&pch);
511         if (sum != hdr->Crc)
512         {
513                 lsx_report("DVMS header checksum error, read %u, calculated %u",
514                      hdr->Crc, sum);
515                 return (SOX_EOF);
516         }
517         return (SOX_SUCCESS);
518 }
519 
520 /* ---------------------------------------------------------------------- */
521 
522 /*
523  * note! file must be seekable
524  */
dvms_write_header(sox_format_t * ft,struct dvms_header * hdr)525 static int dvms_write_header(sox_format_t * ft, struct dvms_header *hdr)
526 {
527         unsigned char hdrbuf[DVMS_HEADER_LEN];
528         unsigned char *pch = hdrbuf;
529         unsigned char *pchs = hdrbuf;
530         int i;
531         unsigned sum;
532 
533         memcpy(pch, hdr->Filename, sizeof(hdr->Filename));
534         pch += sizeof(hdr->Filename);
535         put16_le(&pch, hdr->Id);
536         put16_le(&pch, hdr->State);
537         put32_le(&pch, (unsigned)hdr->Unixtime);
538         put16_le(&pch, hdr->Usender);
539         put16_le(&pch, hdr->Ureceiver);
540         put32_le(&pch, (unsigned) hdr->Length);
541         put16_le(&pch, hdr->Srate);
542         put16_le(&pch, hdr->Days);
543         put16_le(&pch, hdr->Custom1);
544         put16_le(&pch, hdr->Custom2);
545         memcpy(pch, hdr->Info, sizeof(hdr->Info));
546         pch += sizeof(hdr->Info);
547         memcpy(pch, hdr->extend, sizeof(hdr->extend));
548         pch += sizeof(hdr->extend);
549         for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
550                 sum += *pchs++;
551         hdr->Crc = sum;
552         put16_le(&pch, hdr->Crc);
553         if (lsx_seeki(ft, (off_t)0, SEEK_SET) < 0)
554         {
555                 lsx_report("seek failed\n: %s",strerror(errno));
556                 return (SOX_EOF);
557         }
558         if (lsx_writebuf(ft, hdrbuf, sizeof(hdrbuf)) != sizeof(hdrbuf))
559         {
560                 lsx_report("%s",strerror(errno));
561                 return (SOX_EOF);
562         }
563         return (SOX_SUCCESS);
564 }
565 
566 /* ---------------------------------------------------------------------- */
567 
make_dvms_hdr(sox_format_t * ft,struct dvms_header * hdr)568 static void make_dvms_hdr(sox_format_t * ft, struct dvms_header *hdr)
569 {
570         priv_t *p = (priv_t *) ft->priv;
571         size_t len;
572         char * comment = lsx_cat_comments(ft->oob.comments);
573 
574         memset(hdr->Filename, 0, sizeof(hdr->Filename));
575         len = strlen(ft->filename);
576         if (len >= sizeof(hdr->Filename))
577                 len = sizeof(hdr->Filename)-1;
578         memcpy(hdr->Filename, ft->filename, len);
579         hdr->Id = hdr->State = 0;
580         hdr->Unixtime = sox_globals.repeatable? 0 : time(NULL);
581         hdr->Usender = hdr->Ureceiver = 0;
582         hdr->Length = p->bytes_written;
583         hdr->Srate = p->cvsd_rate/100;
584         hdr->Days = hdr->Custom1 = hdr->Custom2 = 0;
585         memset(hdr->Info, 0, sizeof(hdr->Info));
586         len = strlen(comment);
587         if (len >= sizeof(hdr->Info))
588                 len = sizeof(hdr->Info)-1;
589         memcpy(hdr->Info, comment, len);
590         memset(hdr->extend, 0, sizeof(hdr->extend));
591         free(comment);
592 }
593 
594 /* ---------------------------------------------------------------------- */
595 
lsx_dvmsstartread(sox_format_t * ft)596 int lsx_dvmsstartread(sox_format_t * ft)
597 {
598         struct dvms_header hdr;
599         int rc;
600 
601         rc = dvms_read_header(ft, &hdr);
602         if (rc){
603             lsx_fail_errno(ft,SOX_EHDR,"unable to read DVMS header");
604             return rc;
605         }
606 
607         lsx_debug("DVMS header of source file \"%s\":", ft->filename);
608         lsx_debug("  filename  \"%.14s\"", hdr.Filename);
609         lsx_debug("  id        0x%x", hdr.Id);
610         lsx_debug("  state     0x%x", hdr.State);
611         lsx_debug("  time      %s", ctime(&hdr.Unixtime)); /* ctime generates lf */
612         lsx_debug("  usender   %u", hdr.Usender);
613         lsx_debug("  ureceiver %u", hdr.Ureceiver);
614         lsx_debug("  length    %" PRIuPTR, hdr.Length);
615         lsx_debug("  srate     %u", hdr.Srate);
616         lsx_debug("  days      %u", hdr.Days);
617         lsx_debug("  custom1   %u", hdr.Custom1);
618         lsx_debug("  custom2   %u", hdr.Custom2);
619         lsx_debug("  info      \"%.16s\"", hdr.Info);
620         ft->signal.rate = (hdr.Srate < 240) ? 16000 : 32000;
621         lsx_debug("DVMS rate %dbit/s using %gbit/s deviation %g%%",
622                hdr.Srate*100, ft->signal.rate,
623                ((ft->signal.rate - hdr.Srate*100) * 100) / ft->signal.rate);
624         rc = lsx_cvsdstartread(ft);
625         if (rc)
626             return rc;
627 
628         return(SOX_SUCCESS);
629 }
630 
631 /* ---------------------------------------------------------------------- */
632 
lsx_dvmsstartwrite(sox_format_t * ft)633 int lsx_dvmsstartwrite(sox_format_t * ft)
634 {
635         struct dvms_header hdr;
636         int rc;
637 
638         rc = lsx_cvsdstartwrite(ft);
639         if (rc)
640             return rc;
641 
642         make_dvms_hdr(ft, &hdr);
643         rc = dvms_write_header(ft, &hdr);
644         if (rc){
645                 lsx_fail_errno(ft,rc,"cannot write DVMS header");
646             return rc;
647         }
648 
649         if (!ft->seekable)
650                lsx_warn("Length in output .DVMS header will wrong since can't seek to fix it");
651 
652         return(SOX_SUCCESS);
653 }
654 
655 /* ---------------------------------------------------------------------- */
656 
lsx_dvmsstopwrite(sox_format_t * ft)657 int lsx_dvmsstopwrite(sox_format_t * ft)
658 {
659         struct dvms_header hdr;
660         int rc;
661 
662         lsx_cvsdstopwrite(ft);
663         if (!ft->seekable)
664         {
665             lsx_warn("File not seekable");
666             return (SOX_EOF);
667         }
668         if (lsx_seeki(ft, (off_t)0, 0) != 0)
669         {
670                 lsx_fail_errno(ft,errno,"Can't rewind output file to rewrite DVMS header.");
671                 return(SOX_EOF);
672         }
673         make_dvms_hdr(ft, &hdr);
674         rc = dvms_write_header(ft, &hdr);
675         if(rc){
676             lsx_fail_errno(ft,rc,"cannot write DVMS header");
677             return rc;
678         }
679         return rc;
680 }
681