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

ss.cc

/*
 * Copyright (c) 1991-1993 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Computer Systems
 *    Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
static const char rcsid[] =
    "@(#) $Header: ss.cc,v 1.12 96/03/23 04:19:29 van Exp $ (LBL)";

#include "config.h"
#include "ss.h"

extern "C" const u_char mulawsum[256*256];
extern "C" const u_char mugaintab[64*256];

static inline int ABS(int i) { return (i < 0? -i : i); }

#define ALL_ZERO ((ULAW_ZERO<<24)|(ULAW_ZERO<<16|(ULAW_ZERO<<8))|ULAW_ZERO)

#define     AGC_FILTER 4            /* 2^4 = 320ms time const. */
#define AGC_CUTOFF 16
#define AGC_GAIN (AGC_FILTER + 3)
#define     AGC_DEADTIME (8*160)          /* adjust every 160ms (time in samples) */

SampleStream::SampleStream(int size, int n, int p, int l) :
      samples(new u_char[n * size]),
      zero(new u_char[size]),
      now(p + size),
      sclock(p + size + random()),
      past(p + size),
      blksize(size),
      totsize(n * size),
      maxsamp((n - 1) * size - p),
      sltmean(0),
      smean(0),
      smax(0),
      doAGC(0),
      bias(0),
      oldbias(0),
      AGClevel(l),
      AGCerr(0),
      deadtime(0),
      ssthresh_(20)
{
      if (maxsamp < (int)blksize)
            abort();

      memset((void *)zero, ULAW_ZERO, blksize);
      memset(samples, ULAW_ZERO, totsize);
}

SampleStream::SampleStream(const SampleStream& s) :
      samples(new u_char[s.totsize]),
      zero(new u_char[s.blksize]),
      now(s.past),
      sclock(s.past + random()),
      past(s.past),
      blksize(s.blksize),
      totsize(s.totsize),
      maxsamp(s.maxsamp),
      sltmean(0),
      smean(0),
      smax(0),
      doAGC(0),
      bias(0),
      oldbias(0),
      AGClevel(s.AGClevel),
      AGCerr(0),
      deadtime(0),
      ssthresh_(s.ssthresh_)
{
      memset((void *)zero, ULAW_ZERO, blksize);
      memset(samples, ULAW_ZERO, totsize);
}

void SampleStream::Compute()
{
      /*
       * compute short term max power (max of 8 sample means) and
       * long term power (full frame mean passed through simple
       * lowpass filter).  This is done for every input & output
       * frame so it should be reasonably efficient.  We take advantage
       * of the fact that frames are 8-byte aligned (at least) and
       * of the u-law sign-magnitude representation to do several
       * sums 'in parallel'.
       */
      register int b = blksize;
      register int amt = b >> 3, max = 0, sum = 0;
      register const u_int *ip = (const u_int*)&samples[now];

      register int mask = 0x007f007f;
      do {
            register int s0 = ~ip[0];
            register int s1 = ~ip[1];
            ip += 2;
            register int p;
            p  = s0 & mask;
            p += (s0 >> 8) & mask;
            p += s1 & mask;
            p += (s1 >> 8) & mask;
            p = ((p >> 16) + p) & 0x3ff;
            if (p > max)
                  max = p;
            sum += p;
      } while (--amt > 0);
      smax = max;
      sum /= b;
      smean = sum;
      register int sm = sltmean;
      register int ssm = sm >> MEAN_FILTER;
      sm += sum - ssm;
      sltmean = sm;
}

void SampleStream::_UpdateAGC()
{
      register int sm = sltmean;

      if (sm >= (AGC_CUTOFF << MEAN_FILTER) &&
          smax - sm >= (ssthresh_ << MEAN_FILTER)) {
            register int ssm = sm >> MEAN_FILTER;
            register int err = AGClevel - ssm;
            AGCerr += err - (AGCerr >> AGC_FILTER);
            register int abserr = ABS(AGCerr);
            if (int(sclock - deadtime) >= 0 &&
                (abserr >> (AGC_GAIN-1)) > 0) {
                  deadtime = sclock + AGC_DEADTIME;
                  AdjustScale((AGCerr + AGC_GAIN/2) >> AGC_GAIN);
            }
      }
}

static inline const u_int* doMix(u_int* sp, const u_int* ip, int len)
{
      const u_char* const mixtab = mulawsum;
      register u_int bmask = 0xff00;
      register u_int allzero = ALL_ZERO;

      for (register u_int* ep = sp + (len >> 2); sp < ep; ++ip, ++sp) {
            register u_int mixsum;
            register u_int idat = *ip;
            register u_int sdat = *sp;

            // special case all zeros since they happen often
            if (idat == allzero)
                  continue;
            if (sdat == allzero)
                  mixsum = idat;
            else {
                  register u_int sb = (sdat >> 16) & bmask;
                  register u_char ib = idat >> 24;
                  mixsum =  mixtab[sb | ib] << 24;
                  sb = (sdat >> 8) & bmask;
                  ib = idat >> 16;
                  mixsum |=  mixtab[sb | ib] << 16;
                  sb = sdat & bmask;
                  ib = idat >> 8;
                  mixsum |=  mixtab[sb | ib] << 8;
                  sb = (sdat << 8) & bmask;
                  ib = idat;
                  mixsum |=  mixtab[sb | ib];
            }
            *sp = mixsum;
      }
      return (ip);
}

static inline const u_int* doBiasedMix(u_int* sp, const u_int* ip, int len,
                               int b)
{
      const u_char* const mixtab = mulawsum;
      const u_char* const gaintab = &mugaintab[(b + 32) << 8];
      register u_int bmask = 0xff00;
      register u_int allzero = ALL_ZERO;

      for (register u_int* ep = sp + (len >> 2); sp < ep; ++ip, ++sp) {
            register u_int mixsum;
            register u_int idat = *ip;
            register u_int sdat = *sp;

            // special case all zeros since they happen often
            if (idat == allzero)
                  continue;

            register u_int sb = (sdat >> 16) & bmask;
            register u_char ib = idat >> 24;
            mixsum =  mixtab[sb | gaintab[ib]] << 24;
            sb = (sdat >> 8) & bmask;
            ib = idat >> 16;
            mixsum |=  mixtab[sb | gaintab[ib]] << 16;
            sb = sdat & bmask;
            ib = idat >> 8;
            mixsum |=  mixtab[sb | gaintab[ib]] << 8;
            sb = (sdat << 8) & bmask;
            ib = idat;
            mixsum |=  mixtab[sb | gaintab[ib]];
            *sp = mixsum;
      }
      return (ip);
}

#ifdef COMPRESSION
static inline const
u_int* doCompressedMix(u_int* sp, const u_int* ip, int len, int level)
{
      int power = 0;
      int i = len / 4;
      register int mask = 0x007f007f;
      const u_int *p = ip;
      do {
            register int s = ~*p++;
            power += s & mask;
            s >>= 8;
            power += s & mask;
      } while (--i > 0);
      double pin = (power >> 16) + (power & 0xffff);
      pin = pin / (16 * len) + 4.94692243;
      extern double CompressionSlope;
      double pout = pin * CompressionSlope + 
            (1 - CompressionSlope) * double(level) / 6.4;
      int gain = irint(32. / 4. * (pout - pin));
      if (gain < -32)
            gain = -32;
      else if (gain > 31)
            gain = 31;

      return doBiasedMix(sp, ip, len, gain);
}
#endif

void SampleStream::Mix(int delta, const u_char *in, int len)
{
      register u_int off;
      register const u_int* ip = (const u_int*)in;

      off = now + delta;
      if (off >= totsize)
            off -= totsize;

      register u_int* sp = (u_int*)&samples[off];
      if (off + len > totsize) {
            /*
             * The thing we're mixing in overlaps the wrap at the
             * end of the stream -- do the first piece (the one
             * that goes to the end of the stream).
             */
            register int i = totsize - off;
            len -= i;
#ifndef COMPRESSION
            if (bias)
                  ip = doBiasedMix(sp, ip, i, bias);
#else
            if (doAGC)
                  ip = doCompressedMix(sp, ip, i, AGClevel);
#endif
            else
                  ip = doMix(sp, ip, i);
            sp = (u_int*)samples;
      }
#ifndef COMPRESSION
      if (bias)
            doBiasedMix(sp, ip, len, bias);
#else
      if (doAGC)
            doCompressedMix(sp, ip, len, AGClevel);
#endif
      else
            doMix(sp, ip, len);
}

Generated by  Doxygen 1.6.0   Back to index