📄 cvsd.c
字号:
/* * CVSD (Continuously Variable Slope Delta modulation) * conversion routines * * The CVSD format is described in the MIL Std 188 113, which is * available from http://bbs.itsi.disa.mil:5580/T3564 * * Copyright (C) 1996 * Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA) * Swiss Federal Institute of Technology, Electronics Lab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * Change History: * * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com) * Fixed compile warnings reported by Kjetil Torgrim Homme * <kjetilho@ifi.uio.no> * * *//* ---------------------------------------------------------------------- */#include <limits.h>#include <math.h>#include <string.h>#include <time.h>#ifndef SEEK_SET#define SEEK_SET 0 /* nasty nasty */#endif /* SEEK_SET */#include "cvsdfilt.h"#include "st.h"#include "libst.h"/* ---------------------------------------------------------------------- */#ifdef NEED_MEMMOVE#define memmove(dest,src,len) (bcopy((src),(dest),(len)))#endif/* ---------------------------------------------------------------------- *//* * private data structures */struct cvsd_common_state { unsigned overload; float mla_int; float mla_tc0; float mla_tc1; unsigned phase; unsigned phase_inc; float v_min, v_max;};struct cvsd_decode_state { float output_filter[DEC_FILTERLEN];};struct cvsd_encode_state { float recon_int; float input_filter[ENC_FILTERLEN];};struct cvsdpriv { struct cvsd_common_state com; union { struct cvsd_decode_state dec; struct cvsd_encode_state enc; } c; struct { unsigned shreg; unsigned mask; unsigned cnt; } bit; unsigned bytes_written; unsigned cvsd_rate; char swapbits;};/* ---------------------------------------------------------------------- */float float_conv(fp1, fp2, n)float *fp1;float *fp2;int n;{ float res = 0; for(; n > 0; n--) res += (*fp1++) * (*fp2++); return res;}/* ---------------------------------------------------------------------- *//* * some remarks about the implementation of the CVSD decoder * the principal integrator is integrated into the output filter * to achieve this, the coefficients of the output filter are multiplied * with (1/(1-1/z)) in the initialisation code. * the output filter must have a sharp zero at f=0 (i.e. the sum of the * filter parameters must be zero). This prevents an accumulation of * DC voltage at the principal integration. *//* ---------------------------------------------------------------------- */static void cvsdstartcommon(ft)ft_t ft;{ struct cvsdpriv *p = (struct cvsdpriv *) ft->priv; /* sanity check */ if (sizeof(struct cvsdpriv) > PRIVSIZE) fail("struct cvsdpriv is too big (%d); change PRIVSIZE in st.h and recompile sox", sizeof(struct cvsdpriv)); p->cvsd_rate = (ft->info.rate <= 24000) ? 16000 : 32000; ft->info.rate = 8000; ft->info.channels = 1; ft->info.size = WORD; /* make output format default to words */ ft->info.style = SIGN2; p->swapbits = ft->swap; ft->swap = 0; /* * initialize the decoder */ p->com.overload = 0x5; p->com.mla_int = 0; /* * timeconst = (1/e)^(200 / SR) = exp(-200/SR) * SR is the sampling rate */ p->com.mla_tc0 = exp((-200.0)/((float)(p->cvsd_rate))); /* * phase_inc = 32000 / SR */ p->com.phase_inc = 32000 / p->cvsd_rate; /* * initialize bit shift register */ p->bit.shreg = p->bit.cnt = 0; p->bit.mask = p->swapbits ? 0x80 : 1; /* * count the bytes written */ p->bytes_written = 0; p->com.v_min = 1; p->com.v_max = -1; report("cvsd: bit rate %dbit/s, bits from %s\n", p->cvsd_rate, p->swapbits ? "msb to lsb" : "lsb to msb");}/* ---------------------------------------------------------------------- */void cvsdstartread(ft) ft_t ft;{ struct cvsdpriv *p = (struct cvsdpriv *) ft->priv; float *fp1; int i; cvsdstartcommon(ft); p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0); p->com.phase = 0; /* * initialize the output filter coeffs (i.e. multiply * the coeffs with (1/(1-1/z)) to achieve integration * this is now done in the filter parameter generation utility */ /* * zero the filter */ for(fp1 = p->c.dec.output_filter, i = DEC_FILTERLEN; i > 0; i--) *fp1++ = 0;}/* ---------------------------------------------------------------------- */void cvsdstartwrite(ft) ft_t ft;{ struct cvsdpriv *p = (struct cvsdpriv *) ft->priv; float *fp1; int i; cvsdstartcommon(ft); p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0); p->com.phase = 4; /* * zero the filter */ for(fp1 = p->c.enc.input_filter, i = ENC_FILTERLEN; i > 0; i--) *fp1++ = 0; p->c.enc.recon_int = 0;}/* ---------------------------------------------------------------------- */voidcvsdstopwrite(ft)ft_t ft;{ struct cvsdpriv *p = (struct cvsdpriv *) ft->priv; if (p->bit.cnt) { putc(p->bit.shreg, ft->fp); p->bytes_written++; } report("cvsd: min slope %f, max slope %f\n", p->com.v_min, p->com.v_max); }/* ---------------------------------------------------------------------- */voidcvsdstopread(ft)ft_t ft;{ struct cvsdpriv *p = (struct cvsdpriv *) ft->priv; report("cvsd: min value %f, max value %f\n", p->com.v_min, p->com.v_max);}/* ---------------------------------------------------------------------- */#undef DEBUG#ifdef DEBUGstatic struct { FILE *f1; FILE *f2; int cnt} dbg = { NULL, NULL, 0 };#endifLONG cvsdread(ft, buf, nsamp) ft_t ft;LONG *buf, nsamp;{ struct cvsdpriv *p = (struct cvsdpriv *) ft->priv; int done = 0; float oval; #ifdef DEBUG if (!dbg.f1) { if (!(dbg.f1 = fopen("dbg1", "w"))) fail("debugging"); fprintf(dbg.f1, "\"input\"\n"); } if (!dbg.f2) { if (!(dbg.f2 = fopen("dbg2", "w"))) fail("debugging"); fprintf(dbg.f2, "\"recon\"\n"); }#endif while (done < nsamp) { if (!p->bit.cnt) { p->bit.shreg = getc(ft->fp); if (feof(ft->fp)) return done; p->bit.cnt = 8; p->bit.mask = p->swapbits ? 0x80 : 1; } /* * handle one bit */ p->bit.cnt--; p->com.overload = ((p->com.overload << 1) | (!!(p->bit.shreg & p->bit.mask))) & 7; if (p->swapbits) p->bit.mask >>= 1; else p->bit.mask <<= 1; p->com.mla_int *= p->com.mla_tc0; if ((p->com.overload == 0) || (p->com.overload == 7)) p->com.mla_int += p->com.mla_tc1; memmove(p->c.dec.output_filter+1, p->c.dec.output_filter, sizeof(p->c.dec.output_filter)-sizeof(float)); if (p->com.overload & 1) p->c.dec.output_filter[0] = p->com.mla_int; else p->c.dec.output_filter[0] = -p->com.mla_int; /* * check if the next output is due */ p->com.phase += p->com.phase_inc; if (p->com.phase >= 4) { oval = float_conv(p->c.dec.output_filter, (p->cvsd_rate < 24000) ? dec_filter_16 : dec_filter_32, DEC_FILTERLEN);#ifdef DEBUG fprintf(dbg.f1, "%f %f\n", (double)dbg.cnt, (double)p->com.mla_int); fprintf(dbg.f2, "%f %f\n", (double)dbg.cnt, (double)oval); dbg.cnt++;#endif if (oval > p->com.v_max) p->com.v_max = oval; if (oval < p->com.v_min) p->com.v_min = oval; *buf++ = (oval * ((float)LONG_MAX)); done++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -