1 /* libSoX CVSD (Continuously Variable Slope Delta modulation)
4 * The CVSD format is described in the MIL Std 188 113, which is
5 * available from http://bbs.itsi.disa.mil:5580/T3564
8 * Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA)
9 * Swiss Federal Institute of Technology, Electronics Lab
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.
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.
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
27 * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com)
28 * Fixed compile warnings reported by Kjetil Torgrim Homme
29 * <kjetilho@ifi.uio.no>
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.
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.
51 /* ---------------------------------------------------------------------- */
53 * private data structures
56 typedef cvsd_priv_t priv_t
;
58 static int debug_count
= 0;
60 /* ---------------------------------------------------------------------- */
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)
72 res += (*fp1++) * (*fp2++);
77 static float float_conv_enc(float const *fp1
, float const *fp2
)
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.
83 * fp1 should be the enc.input_filter array and must be
84 * CVSD_ENC_FILTERLEN (16) long.
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
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];
113 static float float_conv_dec(float const *fp1
, float const *fp2
)
115 /* This is a specialzed version of float_conv() for decoding
116 * which assumes a specific length and structure to the data
119 * fp1 should be the dec.output_filter array and must be
120 * CVSD_DEC_FILTERLEN (48) long.
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).
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];
160 /* ---------------------------------------------------------------------- */
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.
170 /* ---------------------------------------------------------------------- */
172 static void cvsdstartcommon(sox_format_t
* ft
)
174 priv_t
*p
= (priv_t
*) ft
->priv
;
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);
181 * initialize the decoder
183 p
->com
.overload
= 0x5;
186 * timeconst = (1/e)^(200 / SR) = exp(-200/SR)
187 * SR is the sampling rate
189 p
->com
.mla_tc0
= exp((-200.0)/((float)(p
->cvsd_rate
)));
191 * phase_inc = 32000 / SR
193 p
->com
.phase_inc
= 32000 / p
->cvsd_rate
;
195 * initialize bit shift register
197 p
->bit
.shreg
= p
->bit
.cnt
= 0;
200 * count the bytes written
202 p
->bytes_written
= 0;
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");
209 /* ---------------------------------------------------------------------- */
211 int lsx_cvsdstartread(sox_format_t
* ft
)
213 priv_t
*p
= (priv_t
*) ft
->priv
;
219 p
->com
.mla_tc1
= 0.1 * (1 - p
->com
.mla_tc0
);
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
229 for(fp1
= p
->c
.dec
.output_filter
, i
= CVSD_DEC_FILTERLEN
*2; i
> 0; i
--)
231 /* initialize mirror circular buffer offset to anything sane. */
232 p
->c
.dec
.offset
= CVSD_DEC_FILTERLEN
- 1;
234 return (SOX_SUCCESS
);
237 /* ---------------------------------------------------------------------- */
239 int lsx_cvsdstartwrite(sox_format_t
* ft
)
241 priv_t
*p
= (priv_t
*) ft
->priv
;
247 p
->com
.mla_tc1
= 0.1 * (1 - p
->com
.mla_tc0
);
252 for(fp1
= p
->c
.enc
.input_filter
, i
= CVSD_ENC_FILTERLEN
*2; i
> 0; i
--)
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;
261 /* ---------------------------------------------------------------------- */
263 int lsx_cvsdstopwrite(sox_format_t
* ft
)
265 priv_t
*p
= (priv_t
*) ft
->priv
;
268 lsx_writeb(ft
, p
->bit
.shreg
);
271 lsx_debug("cvsd: min slope %f, max slope %f",
272 p
->com
.v_min
, p
->com
.v_max
);
274 return (SOX_SUCCESS
);
277 /* ---------------------------------------------------------------------- */
279 int lsx_cvsdstopread(sox_format_t
* ft
)
281 priv_t
*p
= (priv_t
*) ft
->priv
;
283 lsx_debug("cvsd: min value %f, max value %f",
284 p
->com
.v_min
, p
->com
.v_max
);
289 /* ---------------------------------------------------------------------- */
291 size_t lsx_cvsdread(sox_format_t
* ft
, sox_sample_t
*buf
, size_t nsamp
)
293 priv_t
*p
= (priv_t
*) ft
->priv
;
297 while (done
< nsamp
) {
299 if (lsx_read_b_buf(ft
, &(p
->bit
.shreg
), (size_t) 1) != 1)
308 p
->com
.overload
= ((p
->com
.overload
<< 1) |
309 (!!(p
->bit
.shreg
& p
->bit
.mask
))) & 7;
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
;
315 /* shift output filter window in mirror cirular buffer. */
316 if (p
->c
.dec
.offset
!= 0)
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)
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
;
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
;
332 * check if the next output is due
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
);
344 if (oval
> p
->com
.v_max
)
346 if (oval
< p
->com
.v_min
)
348 *buf
++ = (oval
* ((float)SOX_SAMPLE_MAX
));
356 /* ---------------------------------------------------------------------- */
358 size_t lsx_cvsdwrite(sox_format_t
* ft
, const sox_sample_t
*buf
, size_t nsamp
)
360 priv_t
*p
= (priv_t
*) ft
->priv
;
366 * check if the next input is due
368 if (p
->com
.phase
>= 4) {
372 /* shift input filter window in mirror cirular buffer. */
373 if (p
->c
.enc
.offset
!= 0)
375 else p
->c
.enc
.offset
= CVSD_ENC_FILTERLEN
- 1;
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
] =
382 ((float)SOX_SAMPLE_MAX
);
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
]));
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
;
408 p
->c
.enc
.recon_int
-= p
->com
.mla_int
;
409 if ((++(p
->bit
.cnt
)) >= 8) {
410 lsx_writeb(ft
, p
->bit
.shreg
);
412 p
->bit
.shreg
= p
->bit
.cnt
= 0;
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
);
423 /* ---------------------------------------------------------------------- */
428 /* FIXME: eliminate these 4 functions */
430 static uint32_t get32_le(unsigned char **p
)
432 uint32_t val
= (((*p
)[3]) << 24) | (((*p
)[2]) << 16) |
433 (((*p
)[1]) << 8) | (**p
);
438 static uint16_t get16_le(unsigned char **p
)
440 unsigned val
= (((*p
)[1]) << 8) | (**p
);
445 static void put32_le(unsigned char **p
, uint32_t val
)
447 *(*p
)++ = val
& 0xff;
448 *(*p
)++ = (val
>> 8) & 0xff;
449 *(*p
)++ = (val
>> 16) & 0xff;
450 *(*p
)++ = (val
>> 24) & 0xff;
453 static void put16_le(unsigned char **p
, unsigned val
)
455 *(*p
)++ = val
& 0xff;
456 *(*p
)++ = (val
>> 8) & 0xff;
476 #define DVMS_HEADER_LEN 120
478 /* ---------------------------------------------------------------------- */
480 static int dvms_read_header(sox_format_t
* ft
, struct dvms_header
*hdr
)
482 unsigned char hdrbuf
[DVMS_HEADER_LEN
];
483 unsigned char *pch
= hdrbuf
;
487 if (lsx_readbuf(ft
, hdrbuf
, sizeof(hdrbuf
)) != sizeof(hdrbuf
))
491 for(i
= sizeof(hdrbuf
), sum
= 0; i
> /*2*/3; i
--) /* Deti bug */
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
);
513 lsx_report("DVMS header checksum error, read %u, calculated %u",
517 return (SOX_SUCCESS
);
520 /* ---------------------------------------------------------------------- */
523 * note! file must be seekable
525 static int dvms_write_header(sox_format_t
* ft
, struct dvms_header
*hdr
)
527 unsigned char hdrbuf
[DVMS_HEADER_LEN
];
528 unsigned char *pch
= hdrbuf
;
529 unsigned char *pchs
= hdrbuf
;
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 */
552 put16_le(&pch
, hdr
->Crc
);
553 if (lsx_seeki(ft
, (off_t
)0, SEEK_SET
) < 0)
555 lsx_report("seek failed\n: %s",strerror(errno
));
558 if (lsx_writebuf(ft
, hdrbuf
, sizeof(hdrbuf
)) != sizeof(hdrbuf
))
560 lsx_report("%s",strerror(errno
));
563 return (SOX_SUCCESS
);
566 /* ---------------------------------------------------------------------- */
568 static void make_dvms_hdr(sox_format_t
* ft
, struct dvms_header
*hdr
)
570 priv_t
*p
= (priv_t
*) ft
->priv
;
572 char * comment
= lsx_cat_comments(ft
->oob
.comments
);
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
));
594 /* ---------------------------------------------------------------------- */
596 int lsx_dvmsstartread(sox_format_t
* ft
)
598 struct dvms_header hdr
;
601 rc
= dvms_read_header(ft
, &hdr
);
603 lsx_fail_errno(ft
,SOX_EHDR
,"unable to read DVMS header");
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
);
631 /* ---------------------------------------------------------------------- */
633 int lsx_dvmsstartwrite(sox_format_t
* ft
)
635 struct dvms_header hdr
;
638 rc
= lsx_cvsdstartwrite(ft
);
642 make_dvms_hdr(ft
, &hdr
);
643 rc
= dvms_write_header(ft
, &hdr
);
645 lsx_fail_errno(ft
,rc
,"cannot write DVMS header");
650 lsx_warn("Length in output .DVMS header will wrong since can't seek to fix it");
655 /* ---------------------------------------------------------------------- */
657 int lsx_dvmsstopwrite(sox_format_t
* ft
)
659 struct dvms_header hdr
;
662 lsx_cvsdstopwrite(ft
);
665 lsx_warn("File not seekable");
668 if (lsx_seeki(ft
, (off_t
)0, 0) != 0)
670 lsx_fail_errno(ft
,errno
,"Can't rewind output file to rewrite DVMS header.");
673 make_dvms_hdr(ft
, &hdr
);
674 rc
= dvms_write_header(ft
, &hdr
);
676 lsx_fail_errno(ft
,rc
,"cannot write DVMS header");