home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Sound / SoX / Source / cvsd.c < prev    next >
C/C++ Source or Header  |  1999-07-18  |  16KB  |  638 lines

  1. /*
  2.  *      CVSD (Continuously Variable Slope Delta modulation)
  3.  *      conversion routines
  4.  *
  5.  *      The CVSD format is described in the MIL Std 188 113, which is
  6.  *      available from http://bbs.itsi.disa.mil:5580/T3564
  7.  *
  8.  *    Copyright (C) 1996  
  9.  *      Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA)
  10.  *      Swiss Federal Institute of Technology, Electronics Lab
  11.  *
  12.  *    This program is free software; you can redistribute it and/or modify
  13.  *    it under the terms of the GNU General Public License as published by
  14.  *    the Free Software Foundation; either version 2 of the License, or
  15.  *    (at your option) any later version.
  16.  *
  17.  *    This program is distributed in the hope that it will be useful,
  18.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  *    GNU General Public License for more details.
  21.  *
  22.  *    You should have received a copy of the GNU General Public License
  23.  *    along with this program; if not, write to the Free Software
  24.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  *
  26.  *
  27.  * Change History:
  28.  *
  29.  * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com)
  30.  *   Fixed compile warnings reported by Kjetil Torgrim Homme
  31.  *   <kjetilho@ifi.uio.no>
  32.  *
  33.  *
  34.  */
  35.  
  36. /* ---------------------------------------------------------------------- */
  37.  
  38. #include <limits.h>
  39. #include <math.h>
  40. #include <string.h>
  41. #include <time.h>
  42. #include <stdio.h>
  43.  
  44. #ifdef HAVE_UNISTD_H
  45. #include <unistd.h>    /* For SEEK_* defines if not found in stdio */
  46. #endif
  47.  
  48. #include "cvsdfilt.h"
  49. #include "st.h"
  50. #include "libst.h"
  51.  
  52. /* ---------------------------------------------------------------------- */
  53.  
  54. #ifndef HAVE_MEMMOVE
  55. #define memmove(dest,src,len) (bcopy((src),(dest),(len)))
  56. #endif
  57.  
  58. /* ---------------------------------------------------------------------- */
  59. /*
  60.  * private data structures
  61.  */
  62.  
  63. struct cvsd_common_state {
  64.     unsigned overload;
  65.     float mla_int;
  66.     float mla_tc0;
  67.     float mla_tc1;
  68.     unsigned phase;
  69.     unsigned phase_inc;
  70.     float v_min, v_max;
  71. };
  72.  
  73. struct cvsd_decode_state {
  74.     float output_filter[DEC_FILTERLEN];
  75. };
  76.  
  77. struct cvsd_encode_state {
  78.     float recon_int;
  79.     float input_filter[ENC_FILTERLEN];
  80. };
  81.  
  82. struct cvsdpriv {
  83.     struct cvsd_common_state com;
  84.     union {
  85.         struct cvsd_decode_state dec;
  86.         struct cvsd_encode_state enc;
  87.     } c;
  88.     struct {
  89.         unsigned shreg;
  90.         unsigned mask;
  91.         unsigned cnt;
  92.     } bit;
  93.     unsigned bytes_written;
  94.     unsigned cvsd_rate;
  95.     char swapbits;
  96. };
  97.  
  98. /* ---------------------------------------------------------------------- */
  99.  
  100. float float_conv(fp1, fp2, n)
  101. float *fp1;
  102. float *fp2;
  103. int n;
  104. {
  105.     float res = 0;
  106.     for(; n > 0; n--)
  107.         res += (*fp1++) * (*fp2++);
  108.     return res;
  109. }
  110.  
  111. /* ---------------------------------------------------------------------- */
  112. /*
  113.  * some remarks about the implementation of the CVSD decoder
  114.  * the principal integrator is integrated into the output filter
  115.  * to achieve this, the coefficients of the output filter are multiplied
  116.  * with (1/(1-1/z)) in the initialisation code.
  117.  * the output filter must have a sharp zero at f=0 (i.e. the sum of the
  118.  * filter parameters must be zero). This prevents an accumulation of
  119.  * DC voltage at the principal integration.
  120.  */
  121. /* ---------------------------------------------------------------------- */
  122.  
  123. static void cvsdstartcommon(ft)
  124. ft_t ft;
  125. {
  126.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  127.     
  128.     /* sanity check */
  129.     if (sizeof(struct cvsdpriv) > PRIVSIZE)
  130.         fail("struct cvsdpriv is too big (%d); change PRIVSIZE in st.h and recompile sox", sizeof(struct cvsdpriv));
  131.     p->cvsd_rate = (ft->info.rate <= 24000) ? 16000 : 32000;
  132.     ft->info.rate = 8000;
  133.     ft->info.channels = 1;
  134.     ft->info.size = WORD; /* make output format default to words */
  135.     ft->info.style = SIGN2;
  136.     p->swapbits = ft->swap;
  137.     ft->swap = 0;
  138.     /*
  139.      * initialize the decoder
  140.      */
  141.     p->com.overload = 0x5;
  142.     p->com.mla_int = 0;
  143.     /*
  144.      * timeconst = (1/e)^(200 / SR) = exp(-200/SR)
  145.      * SR is the sampling rate
  146.      */
  147.     p->com.mla_tc0 = exp((-200.0)/((float)(p->cvsd_rate)));
  148.     /*
  149.      * phase_inc = 32000 / SR
  150.      */
  151.     p->com.phase_inc = 32000 / p->cvsd_rate;
  152.     /*
  153.      * initialize bit shift register
  154.      */
  155.     p->bit.shreg = p->bit.cnt = 0;
  156.     p->bit.mask = p->swapbits ? 0x80 : 1;
  157.     /*
  158.      * count the bytes written
  159.      */
  160.     p->bytes_written = 0;
  161.     p->com.v_min = 1;
  162.     p->com.v_max = -1;
  163.     report("cvsd: bit rate %dbit/s, bits from %s\n", p->cvsd_rate,
  164.            p->swapbits ? "msb to lsb" : "lsb to msb");
  165. }
  166.  
  167. /* ---------------------------------------------------------------------- */
  168.  
  169. void cvsdstartread(ft) 
  170. ft_t ft;
  171. {
  172.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  173.     float *fp1;
  174.     int i;
  175.     
  176.     cvsdstartcommon(ft);
  177.     p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0);
  178.     p->com.phase = 0;
  179.     /*
  180.      * initialize the output filter coeffs (i.e. multiply
  181.      * the coeffs with (1/(1-1/z)) to achieve integration
  182.      * this is now done in the filter parameter generation utility
  183.      */
  184.     /*
  185.      * zero the filter 
  186.      */
  187.     for(fp1 = p->c.dec.output_filter, i = DEC_FILTERLEN; i > 0; i--)
  188.         *fp1++ = 0;
  189. }
  190.  
  191. /* ---------------------------------------------------------------------- */
  192.  
  193. void cvsdstartwrite(ft) 
  194. ft_t ft;
  195. {
  196.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  197.     float *fp1;
  198.     int i;
  199.  
  200.     cvsdstartcommon(ft);
  201.     p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0);
  202.     p->com.phase = 4;
  203.     /*
  204.      * zero the filter 
  205.      */
  206.     for(fp1 = p->c.enc.input_filter, i = ENC_FILTERLEN; i > 0; i--)
  207.         *fp1++ = 0;
  208.     p->c.enc.recon_int = 0;
  209. }
  210.  
  211. /* ---------------------------------------------------------------------- */
  212.  
  213. void
  214. cvsdstopwrite(ft)
  215. ft_t ft;
  216. {
  217.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  218.  
  219.     if (p->bit.cnt) {
  220.         putc(p->bit.shreg, ft->fp);
  221.         p->bytes_written++;
  222.     }
  223.     report("cvsd: min slope %f, max slope %f\n", 
  224.            p->com.v_min, p->com.v_max);    
  225. }
  226.  
  227. /* ---------------------------------------------------------------------- */
  228.  
  229. void
  230. cvsdstopread(ft)
  231. ft_t ft;
  232. {
  233.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  234.  
  235.     report("cvsd: min value %f, max value %f\n", 
  236.            p->com.v_min, p->com.v_max);
  237. }
  238.  
  239. /* ---------------------------------------------------------------------- */
  240.  
  241. #undef DEBUG
  242.  
  243. #ifdef DEBUG
  244. static struct {
  245.     FILE *f1;
  246.     FILE *f2;
  247.     int cnt
  248. } dbg = { NULL, NULL, 0 };
  249. #endif
  250.  
  251. LONG cvsdread(ft, buf, nsamp) 
  252. ft_t ft;
  253. LONG *buf, nsamp;
  254. {
  255.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  256.     int done = 0;
  257.     float oval;
  258.     
  259. #ifdef DEBUG
  260.     if (!dbg.f1) {
  261.         if (!(dbg.f1 = fopen("dbg1", "w")))
  262.             fail("debugging");
  263.         fprintf(dbg.f1, "\"input\"\n");
  264.     }
  265.     if (!dbg.f2) {
  266.         if (!(dbg.f2 = fopen("dbg2", "w")))
  267.             fail("debugging");
  268.         fprintf(dbg.f2, "\"recon\"\n");
  269.     }
  270. #endif
  271.     while (done < nsamp) {
  272.         if (!p->bit.cnt) {
  273.             p->bit.shreg = getc(ft->fp);
  274.             if (feof(ft->fp))
  275.                 return done;
  276.             p->bit.cnt = 8;
  277.             p->bit.mask = p->swapbits ? 0x80 : 1;
  278.         }
  279.         /*
  280.          * handle one bit
  281.          */
  282.         p->bit.cnt--;
  283.         p->com.overload = ((p->com.overload << 1) | 
  284.                    (!!(p->bit.shreg & p->bit.mask))) & 7;
  285.         if (p->swapbits)
  286.             p->bit.mask >>= 1;
  287.         else
  288.             p->bit.mask <<= 1;
  289.         p->com.mla_int *= p->com.mla_tc0;
  290.         if ((p->com.overload == 0) || (p->com.overload == 7))
  291.             p->com.mla_int += p->com.mla_tc1;
  292.         memmove(p->c.dec.output_filter+1, p->c.dec.output_filter,
  293.             sizeof(p->c.dec.output_filter)-sizeof(float));
  294.         if (p->com.overload & 1)
  295.             p->c.dec.output_filter[0] = p->com.mla_int;
  296.         else
  297.             p->c.dec.output_filter[0] = -p->com.mla_int;
  298.         /*
  299.          * check if the next output is due
  300.          */
  301.         p->com.phase += p->com.phase_inc;
  302.         if (p->com.phase >= 4) {
  303.             oval = float_conv(p->c.dec.output_filter, 
  304.                       (p->cvsd_rate < 24000) ? 
  305.                       dec_filter_16 : dec_filter_32, 
  306.                       DEC_FILTERLEN);
  307. #ifdef DEBUG
  308.             fprintf(dbg.f1, "%f %f\n", (double)dbg.cnt, 
  309.                 (double)p->com.mla_int);
  310.             fprintf(dbg.f2, "%f %f\n", (double)dbg.cnt, 
  311.                 (double)oval);
  312.             dbg.cnt++;
  313. #endif        
  314.             if (oval > p->com.v_max)
  315.                 p->com.v_max = oval;
  316.             if (oval < p->com.v_min)
  317.                 p->com.v_min = oval;
  318.             *buf++ = (oval * ((float)LONG_MAX));
  319.             done++;
  320.         }
  321.         p->com.phase &= 3;
  322.     }
  323.     return done;
  324. }
  325.  
  326. /* ---------------------------------------------------------------------- */
  327.  
  328. void
  329. cvsdwrite(ft, buf, nsamp) 
  330. ft_t ft;
  331. LONG *buf, nsamp;
  332. {
  333.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  334.     int done = 0;
  335.     float inval;
  336.  
  337. #ifdef DEBUG
  338.     if (!dbg.f1) {
  339.         if (!(dbg.f1 = fopen("dbg1", "w")))
  340.             fail("debugging");
  341.         fprintf(dbg.f1, "\"input\"\n");
  342.     }
  343.     if (!dbg.f2) {
  344.         if (!(dbg.f2 = fopen("dbg2", "w")))
  345.             fail("debugging");
  346.         fprintf(dbg.f2, "\"recon\"\n");
  347.     }
  348. #endif
  349.     for(;;) {
  350.         /*
  351.          * check if the next input is due
  352.          */
  353.         if (p->com.phase >= 4) {
  354.             if (done >= nsamp)
  355.                 return;
  356.             memmove(p->c.enc.input_filter+1, p->c.enc.input_filter,
  357.                 sizeof(p->c.enc.input_filter)-sizeof(float));
  358.             p->c.enc.input_filter[0] = (*buf++) / 
  359.                 ((float)LONG_MAX);
  360.             done++;
  361.         }
  362.         p->com.phase &= 3;
  363.         /* insert input filter here! */
  364.         inval = float_conv(p->c.enc.input_filter, 
  365.                    (p->cvsd_rate < 24000) ? 
  366.                    (enc_filter_16[(p->com.phase >= 2)]) : 
  367.                    (enc_filter_32[p->com.phase]), 
  368.                    ENC_FILTERLEN);
  369.         /*
  370.          * encode one bit
  371.          */
  372.         p->com.overload = (((p->com.overload << 1) |
  373.                     (inval >  p->c.enc.recon_int)) & 7);
  374.         p->com.mla_int *= p->com.mla_tc0;
  375.         if ((p->com.overload == 0) || (p->com.overload == 7))
  376.             p->com.mla_int += p->com.mla_tc1;
  377.         if (p->com.mla_int > p->com.v_max)
  378.             p->com.v_max = p->com.mla_int;
  379.         if (p->com.mla_int < p->com.v_min)
  380.             p->com.v_min = p->com.mla_int;
  381.         if (p->com.overload & 1) {
  382.             p->c.enc.recon_int += p->com.mla_int;
  383.             p->bit.shreg |= p->bit.mask;
  384.         } else
  385.             p->c.enc.recon_int -= p->com.mla_int;
  386.         if ((++(p->bit.cnt)) >= 8) {
  387.             putc(p->bit.shreg, ft->fp);
  388.             p->bytes_written++;
  389.             p->bit.shreg = p->bit.cnt = 0;
  390.             p->bit.mask = p->swapbits ? 0x80 : 1;
  391.         } else {
  392.             if (p->swapbits)
  393.                 p->bit.mask >>= 1;
  394.             else
  395.                 p->bit.mask <<= 1;
  396.         }
  397.         p->com.phase += p->com.phase_inc;
  398. #ifdef DEBUG
  399.         fprintf(dbg.f1, "%f %f\n", (double)dbg.cnt, (double)inval);
  400.         fprintf(dbg.f2, "%f %f\n", (double)dbg.cnt, 
  401.             (double)p->c.enc.recon_int);
  402.         dbg.cnt++;
  403. #endif    
  404.     }
  405. }
  406.  
  407. /* ---------------------------------------------------------------------- */
  408. /*
  409.  * DVMS file header
  410.  */
  411. struct dvms_header {
  412.     char          Filename[14];
  413.     unsigned      Id;
  414.     unsigned      State;
  415.     time_t        Unixtime;
  416.     unsigned      Usender;
  417.     unsigned      Ureceiver;
  418.     ULONG          Length;
  419.     unsigned      Srate;
  420.     unsigned      Days;
  421.     unsigned      Custom1;
  422.     unsigned      Custom2;
  423.     char          Info[16];
  424.     char          extend[64];
  425.     unsigned      Crc;
  426. };
  427.  
  428. #define DVMS_HEADER_LEN 120
  429.  
  430. /* ---------------------------------------------------------------------- */
  431.  
  432. static ULONG get32(p)
  433. unsigned char **p;
  434. {
  435.     ULONG val = (((*p)[3]) << 24) | (((*p)[2]) << 16) | 
  436.         (((*p)[1]) << 8) | (**p);
  437.     (*p) += 4;
  438.     return val;
  439. }
  440.  
  441. static unsigned get16(p)
  442. unsigned char **p;
  443. {
  444.     unsigned val = (((*p)[1]) << 8) | (**p);
  445.     (*p) += 2;
  446.     return val;
  447. }
  448.  
  449. static void put32(p, val)
  450. unsigned char **p;
  451. ULONG val;
  452. {
  453.     *(*p)++ = val & 0xff;
  454.     *(*p)++ = (val >> 8) & 0xff;
  455.     *(*p)++ = (val >> 16) & 0xff;
  456.     *(*p)++ = (val >> 24) & 0xff;
  457. }
  458.  
  459. static void put16(p, val)
  460. unsigned char **p;
  461. unsigned val;
  462. {
  463.     *(*p)++ = val & 0xff;
  464.     *(*p)++ = (val >> 8) & 0xff;
  465. }
  466.  
  467. /* ---------------------------------------------------------------------- */
  468.  
  469. static void dvms_read_header(f, hdr)
  470. FILE *f;
  471. struct dvms_header *hdr;
  472. {
  473.     unsigned char hdrbuf[DVMS_HEADER_LEN];
  474.     unsigned char *pch = hdrbuf;
  475.     int i;
  476.     unsigned sum;
  477.  
  478.     if (fread(hdrbuf, sizeof(hdrbuf), 1, f) != 1)
  479.         fail("unable to read DVMS header\n");
  480.     for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
  481.         sum += *pch++;
  482.     pch = hdrbuf;
  483.     memcpy(hdr->Filename, pch, sizeof(hdr->Filename));
  484.     pch += sizeof(hdr->Filename);
  485.     hdr->Id = get16(&pch);
  486.     hdr->State = get16(&pch);
  487.     hdr->Unixtime = get32(&pch);
  488.     hdr->Usender = get16(&pch);
  489.     hdr->Ureceiver = get16(&pch);
  490.     hdr->Length = get32(&pch);
  491.     hdr->Srate = get16(&pch);
  492.     hdr->Days = get16(&pch);
  493.     hdr->Custom1 = get16(&pch);
  494.     hdr->Custom2 = get16(&pch);
  495.     memcpy(hdr->Info, pch, sizeof(hdr->Info));
  496.     pch += sizeof(hdr->Info);
  497.     memcpy(hdr->extend, pch, sizeof(hdr->extend));
  498.     pch += sizeof(hdr->extend);
  499.     hdr->Crc = get16(&pch);
  500.     if (sum != hdr->Crc) 
  501.         fail("DVMS header checksum error, read %u, calculated %u\n",
  502.              hdr->Crc, sum);
  503. }
  504.  
  505. /* ---------------------------------------------------------------------- */
  506.  
  507. /*
  508.  * note! file must be seekable
  509.  */
  510. static void dvms_write_header(f, hdr)
  511. FILE *f;
  512. struct dvms_header *hdr;
  513. {
  514.     unsigned char hdrbuf[DVMS_HEADER_LEN];
  515.     unsigned char *pch = hdrbuf;
  516.     unsigned char *pchs = hdrbuf;
  517.     int i;
  518.     unsigned sum;
  519.  
  520.     memcpy(pch, hdr->Filename, sizeof(hdr->Filename));
  521.     pch += sizeof(hdr->Filename);
  522.     put16(&pch, hdr->Id);
  523.     put16(&pch, hdr->State);
  524.     put32(&pch, hdr->Unixtime);
  525.     put16(&pch, hdr->Usender);
  526.     put16(&pch, hdr->Ureceiver);
  527.     put32(&pch, hdr->Length);
  528.     put16(&pch, hdr->Srate);
  529.     put16(&pch, hdr->Days);
  530.     put16(&pch, hdr->Custom1);
  531.     put16(&pch, hdr->Custom2);
  532.     memcpy(pch, hdr->Info, sizeof(hdr->Info));
  533.     pch += sizeof(hdr->Info);
  534.     memcpy(pch, hdr->extend, sizeof(hdr->extend));
  535.     pch += sizeof(hdr->extend);
  536.     for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
  537.         sum += *pchs++;
  538.     hdr->Crc = sum;
  539.     put16(&pch, hdr->Crc);
  540.     if (fseek(f, 0, SEEK_SET) < 0)
  541.         fail("cannot write DVMS header, seek failed\n");
  542.     if (fwrite(hdrbuf, sizeof(hdrbuf), 1, f) != 1)
  543.         fail("cannot write DVMS header\n");
  544. }
  545.  
  546. /* ---------------------------------------------------------------------- */
  547.  
  548. static void make_dvms_hdr(ft, hdr)
  549. ft_t ft;
  550. struct dvms_header *hdr;
  551. {
  552.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  553.     int len;
  554.  
  555.     memset(hdr->Filename, 0, sizeof(hdr->Filename));
  556.     len = strlen(ft->filename);
  557.     if (len >= sizeof(hdr->Filename))
  558.         len = sizeof(hdr->Filename)-1;
  559.     memcpy(hdr->Filename, ft->filename, len);
  560.     hdr->Id = hdr->State = 0;
  561.     hdr->Unixtime = time(NULL);
  562.     hdr->Usender = hdr->Ureceiver = 0;
  563.     hdr->Length = p->bytes_written;
  564.     hdr->Srate = p->cvsd_rate/100;
  565.     hdr->Days = hdr->Custom1 = hdr->Custom2 = 0;
  566.     memset(hdr->Info, 0, sizeof(hdr->Info));
  567.     len = strlen(ft->comment);
  568.     if (len >= sizeof(hdr->Info))
  569.         len = sizeof(hdr->Info)-1;
  570.     memcpy(hdr->Info, ft->comment, len);
  571.     memset(hdr->extend, 0, sizeof(hdr->extend));
  572. }
  573.  
  574. /* ---------------------------------------------------------------------- */
  575.  
  576. void dvmsstartread(ft) 
  577. ft_t ft;
  578. {
  579.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  580.     struct dvms_header hdr;
  581.  
  582.     dvms_read_header(ft->fp, &hdr);
  583.     report("DVMS header of source file \"%s\":");
  584.     report("  filename  \"%.14s\"",ft->filename);
  585.         report("  id        0x%x", hdr.Filename);
  586.     report("  state     0x%x", hdr.Id, hdr.State);
  587.     report("  time      %s",ctime(&hdr.Unixtime)); /* ctime generates lf */
  588.     report("  usender   %u", hdr.Usender);
  589.     report("  ureceiver %u", hdr.Ureceiver);
  590.     report("  length    %u", hdr.Length);
  591.     report("  srate     %u", hdr.Srate);
  592.     report("  days      %u", hdr.Days);
  593.     report("  custom1   %u", hdr.Custom1);
  594.     report("  custom2   %u", hdr.Custom2);
  595.     report("  info      \"%.16s\"\n", hdr.Info);
  596.     ft->info.rate = (hdr.Srate < 240) ? 16000 : 32000;
  597.     report("DVMS rate %dbit/s using %dbit/s deviation %d%%\n", 
  598.            hdr.Srate*100, ft->info.rate, 
  599.            ((ft->info.rate - hdr.Srate*100) * 100) / ft->info.rate);
  600.     cvsdstartread(ft);
  601.     p->swapbits = 0;
  602. }
  603.  
  604. /* ---------------------------------------------------------------------- */
  605.  
  606. void dvmsstartwrite(ft) 
  607. ft_t ft;
  608. {
  609.     struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
  610.     struct dvms_header hdr;
  611.     
  612.     cvsdstartwrite(ft);
  613.     make_dvms_hdr(ft, &hdr);
  614.     dvms_write_header(ft->fp, &hdr);
  615.     if (!ft->seekable)
  616.            warn("Length in output .DVMS header will wrong since can't seek to fix it");
  617.     p->swapbits = 0;
  618. }
  619.  
  620. /* ---------------------------------------------------------------------- */
  621.  
  622. void
  623. dvmsstopwrite(ft)
  624. ft_t ft;
  625. {
  626.     struct dvms_header hdr;
  627.     
  628.     cvsdstopwrite(ft);
  629.     if (!ft->seekable)
  630.         return;
  631.     if (fseek(ft->fp, 0L, 0) != 0)
  632.         fail("Can't rewind output file to rewrite DVMS header.");
  633.     make_dvms_hdr(ft, &hdr);
  634.     dvms_write_header(ft->fp, &hdr);
  635. }
  636.  
  637. /* ---------------------------------------------------------------------- */
  638.