Logo Search packages:      
Sourcecode: baycomepp version File versions  Download package

audio.c

/*****************************************************************************/

/*
 *      audio.c  --  Audio processing for "virtual transceiver".
 *
 *      Copyright (C) 1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
 *
 *      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.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 */

/*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <math.h>

#include "eppfm.h"

/* ---------------------------------------------------------------------- */

#define PWRINTERVAL     4096         /* must be even */
#define PWRINTERVAL2      64         /* must be even */
#define PWRNOISECALIB   4096

/* ---------------------------------------------------------------------- */

struct {
      /* samling rates */
      unsigned int srateepp, sratedsp;
      /* sampling rate converter */
      unsigned int ph, phinc;
      /* power meter */
      unsigned int pwrcnt;
      unsigned int pwracc;
      /* freqency generators */
      unsigned int ph0, ph1, freq0, freq1;
} istate;

struct {
      /* samling rates */
      unsigned int srateepp, sratedsp;
      /* sampling rate converter */
      unsigned int ph, phinc;
      /* power meter */
      unsigned int pwrcnt, pwrcnt2;
      unsigned int pwracc1;
      int pwracc2, pwracc3;
      float pwracc4;
      /* carrier detect state */
      unsigned int dcdparam, dcd;
} ostate;

/* ---------------------------------------------------------------------- */

static const int16_t rxfilter[16][16] = {
      { 139,  -57, -451,  612,  1263, -2887, -2021, 13678, 24449, 12513, -2539, -2588, 1360,  498, -450, -31 },
      { 138,  -85, -445,  728,  1141, -3169, -1432, 14824, 24343, 11337, -2984, -2276, 1432,  385, -443,  -6 },
      { 137, -115, -432,  842,   993, -3427,  -772, 15942, 24131, 10160, -3358, -1956, 1480,  277, -430,  16 },
      { 134, -146, -410,  954,   820, -3657,   -42, 17022, 23817,  8989, -3661, -1632, 1504,  173, -412,  36 },
      { 130, -177, -380, 1061,   623, -3854,   753, 18058, 23401,  7832, -3895, -1309, 1507,   76, -390,  54 },
      { 124, -210, -341, 1161,   402, -4012,  1613, 19040, 22888,  6698, -4062,  -991, 1490,  -15, -365,  71 },
      { 117, -243, -294, 1253,   159, -4127,  2531, 19961, 22282,  5594, -4165,  -682, 1454,  -97, -337,  85 },
      { 108, -275, -237, 1333,  -105, -4194,  3505, 20813, 21589,  4528, -4208,  -386, 1401, -172, -307,  97 },
      {  97, -307, -172, 1401,  -386, -4208,  4528, 21589, 20813,  3505, -4194,  -105, 1333, -237, -275, 108 },
      {  85, -337,  -97, 1454,  -682, -4165,  5594, 22282, 19961,  2531, -4127,   159, 1253, -294, -243, 117 },
      {  71, -365,  -15, 1490,  -991, -4062,  6698, 22888, 19040,  1613, -4012,   402, 1161, -341, -210, 124 },
      {  54, -390,   76, 1507, -1309, -3895,  7832, 23401, 18058,   753, -3854,   623, 1061, -380, -177, 130 },
      {  36, -412,  173, 1504, -1632, -3661,  8989, 23817, 17022,   -42, -3657,   820,  954, -410, -146, 134 },
      {  16, -430,  277, 1480, -1956, -3358, 10160, 24131, 15942,  -772, -3427,   993,  842, -432, -115, 137 },
      {  -6, -443,  385, 1432, -2276, -2984, 11337, 24343, 14824, -1432, -3169,  1141,  728, -445,  -85, 138 },
      { -31, -450,  498, 1360, -2588, -2539, 12513, 24449, 13678, -2021, -2887,  1263,  612, -451,  -57, 139 }
};

#define RXFPH(x)  (((x)>>(PHASEFRAC-4))&15)
#define RXFLEN    16

/* ---------------------------------------------------------------------- */

void audio_1750(int on)
{
      if (on && istate.srateepp > 0)
            istate.freq0 = (1750*65536 + istate.srateepp/2) / istate.srateepp;
      else
            istate.freq0 = 0;
      istate.freq1 = 0;
      istate.ph0 = 0;
      istate.ph1 = 0;
}

/*
 *
 * DTMF frequencies
 *
 *      1209 1336 1477 1633
 *  697   1    2    3    A
 *  770   4    5    6    B
 *  852   7    8    9    C
 *  941   *    0    #    D
 * 
 */

void audio_dtmf(int ch)
{
      static const unsigned char dtmftransl[0x10] = {
            0x13, 0x00, 0x10, 0x20, 0x01, 0x11, 0x21, 0x02,
            0x12, 0x22, 0x30, 0x31, 0x32, 0x33, 0x03, 0x23
      };
      static const unsigned int freqlogrp[4] = { 697, 770, 852, 941 };
      static const unsigned int freqhigrp[4] = { 1209, 1336, 1477, 1633 };
      unsigned int tr;

      if (ch & 16 && istate.sratedsp > 0) {
            tr = dtmftransl[ch & 15];
            istate.freq0 = (freqlogrp[tr & 15]*65536+istate.srateepp/2)/istate.srateepp;
            istate.freq1 = (freqhigrp[tr >> 4]*65536+istate.srateepp/2)/istate.srateepp;
      } else {
            istate.freq0 = 0;
            istate.freq1 = 0;
      }     
      istate.ph0 = 0;
      istate.ph1 = 0;
}

/* ---------------------------------------------------------------------- */

void audio_setsquelch(int sq)
{
      ostate.dcdparam = !!sq;
}

int audio_getsquelch(void)
{
      return ostate.dcd;
}

/* ---------------------------------------------------------------------- */

extern inline int calcfilter(const int16_t *coeff, const int8_t *data)
{
      unsigned cnt;
      int sum = 0;
      
      for (cnt = 0; cnt < RXFLEN; cnt++)
            sum += (*coeff++) * (*data--);
      return sum >> 8;
}

/* ---------------------------------------------------------------------- */

void audio_initinput(unsigned int srateepp, unsigned int sratedsp)
{
      memset(&istate, 0, sizeof(istate));
      istate.srateepp = srateepp;
      istate.sratedsp = sratedsp;
      istate.phinc = ((1 << PHASEFRAC) * sratedsp + srateepp / 2) / srateepp;
      lprintf(2, "rec phase inc: 0x%05x\n", istate.phinc);
}

unsigned int audio_convertinput(unsigned int num, const int16_t *ibuf, signed char *obuf)
{
      unsigned int cnt = 0;
      unsigned int i;
      float pw;
      int s;
      
      for (i = 0; i < num; i++) {
            istate.pwracc += ibuf[i] * ibuf[i];
            if ((++istate.pwrcnt) >= PWRINTERVAL) {
                  pw = istate.pwracc;
                  istate.pwracc = 0;
                  istate.pwrcnt = 0;
                  pw *= (1.0 / PWRINTERVAL);
                  if (pw < 1.6384)
                        pw = -40;
                  else
                        pw = (10.0 / M_LN10) * log(pw) - 42.144;
                  gui_updatevu(pw, -40);
            }
      }
      istate.ph &= PHASEMASK;
      while (istate.ph < (num << PHASEFRAC)) {
            s = ibuf[istate.ph >> PHASEFRAC] >> 8;
            s += SIN(istate.ph0) >> 9;
            s += SIN(istate.ph1) >> 9;
            if (s > 127)
                  s = 127;
            if (s < -128)
                  s = -128;
            obuf[cnt] = s;
            istate.ph += istate.phinc;
            cnt++;
            istate.ph0 += istate.freq0;
            istate.ph1 += istate.freq1;
      }
      gui_addsamples(num, ibuf);
      return cnt;
}

int audio_adjustinput(int eppcnt, int dspcnt, int eppdelay)
{
      lprintf(4, "eppcnt %d dspcnt %d eppdelay %d\n", eppcnt, dspcnt, eppdelay);
      if (eppdelay > SNDLATENCY) {
            istate.phinc++;
            istate.ph += PHASEMASK >> 2;
            if (istate.ph > PHASEMASK)
                  istate.ph = PHASEMASK;
      } else if (eppdelay < SNDLATENCY) {
            istate.phinc--;
            istate.ph -= PHASEMASK >> 2;
            if (istate.ph > PHASEMASK)
                  istate.ph = 0;
      }
      if (istate.phinc < (0x9 << (PHASEFRAC-4)) || istate.phinc > (0x1f << (PHASEFRAC-4))) {
            lprintf(0, "phinc (0x%05x) out of range\n", istate.phinc);
            return -1;
      }
      lprintf(3, "phase increment: 0x%05x\n", istate.phinc);
      return 0;
}

void audio_initoutput(unsigned int srateepp, unsigned int sratedsp)
{
      memset(&ostate, 0, sizeof(ostate));
      ostate.srateepp = srateepp;
      ostate.sratedsp = sratedsp;
      ostate.phinc = ((1 << PHASEFRAC) * srateepp + sratedsp / 2) / sratedsp;
      lprintf(2, "play phase inc: 0x%05x\n", ostate.phinc);
}

unsigned int audio_convertoutput(unsigned int num, const signed char *ibuf, int16_t *obuf)
{
      unsigned int cnt = 0;
      unsigned int i;
      float pw1, pw2;
      
      for (i = 0; i < num; i++) {
            ostate.pwracc1 += ibuf[i] * ibuf[i];
            switch (ostate.pwrcnt2 & 3) {
            case 0:
                  ostate.pwracc2 -= ibuf[i];
                  break;

            case 1:
                  ostate.pwracc3 -= ibuf[i];
                  break;

            case 2:
                  ostate.pwracc2 += ibuf[i];
                  break;

            default:
                  ostate.pwracc3 += ibuf[i];
                  break;
            }
            if ((++ostate.pwrcnt2) >= PWRINTERVAL2) {
                  ostate.pwracc4 += ostate.pwracc2 * ostate.pwracc2 + ostate.pwracc3 * ostate.pwracc3;
                  ostate.pwracc2 = 0;
                  ostate.pwracc3 = 0;
                  ostate.pwrcnt2 = 0;                 
            }
            if ((++ostate.pwrcnt) >= PWRINTERVAL) {
                  pw1 = ostate.pwracc1;
                  pw2 = ostate.pwracc4;
                  ostate.pwracc1 = 0;
                  ostate.pwracc4 = 0;
                  ostate.pwrcnt = 0;
                  pw1 *= (1.0 / PWRINTERVAL);
                  pw2 *= (1.0 / PWRINTERVAL / PWRINTERVAL) * PWRNOISECALIB;
                  if (pw1 < 1.6384)
                        pw1 = -40;
                  else
                        pw1 = (10.0 / M_LN10) * log(pw1) - 42.144;
                  if (pw2 < 1.6384)
                        pw2 = -40;
                  else
                        pw2 = (10.0 / M_LN10) * log(pw2) - 42.144;
                  if (pw2 > 0)
                        pw2 = 0;
                  gui_updatevu(pw1, pw2);
                  ostate.dcd = (pw1 > -30) && (pw2 < (pw1 / 2 - 20));
            }
      }
      ostate.ph &= PHASEMASK;
      while (ostate.ph < (num << PHASEFRAC)) {
#if 0
            obuf[cnt] = ibuf[ostate.ph >> PHASEFRAC] << 8;
#else
            obuf[cnt] = calcfilter(rxfilter[RXFPH(ostate.ph)], ibuf+(ostate.ph >> PHASEFRAC));
#endif
            ostate.ph += ostate.phinc;
            cnt++;
      }
      gui_addsamples(cnt, obuf);
      if (!ostate.dcd && ostate.dcdparam)
            memset(obuf, 0, 2*cnt);
      return cnt;
}

int audio_adjustoutput(int dspcnt, int eppcnt, int dspdelay)
{
      lprintf(4, "dspcnt %d eppcnt %d dspdelay %d\n", dspcnt, eppcnt, dspdelay);
      ostate.ph &= PHASEMASK;
      if (dspdelay > SNDLATENCY) {
            ostate.phinc++;
            ostate.ph += PHASEMASK >> 2;
            if (ostate.ph > PHASEMASK)
                  ostate.ph = PHASEMASK;
      } else if (dspdelay < SNDLATENCY) {
            ostate.phinc--;
            ostate.ph -= PHASEMASK >> 2;
            if (ostate.ph > PHASEMASK)
                  ostate.ph = 0;
      } if (ostate.phinc < (0x9 << (PHASEFRAC-4)) || ostate.phinc > (0x1f << (PHASEFRAC-4))) {
            lprintf(0, "phinc (0x%05x) out of range\n", ostate.phinc);
            return -1;
      }
      lprintf(3, "phase increment: 0x%05x\n", ostate.phinc);
      return 0;
}

/* ---------------------------------------------------------------------- */

Generated by  Doxygen 1.6.0   Back to index