/* * 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: filter.cc,v 1.7 96/03/16 13:12:51 van Exp $ (LBL)"; #include "config.h" #include #include #include "filter.h" #include "mulaw.h" #include "wiener.h" Filter::Filter(Audio *a) { taps = 0; ntaps = 0; audio = a; } Filter::~Filter() { delete taps; taps = 0; } void Filter::Compute(SampleStream *in, u_char *out, int n) { FilterTap* tap = taps; register u_char* blk = in->CurBlk(); if (in->BlkBack(-tap[0].tapno) - blk != tap[0].tapno) { // convolution spans buffer wrap. } else { while (--n >= 0) { register u_long sum = 0; register int t; for ( ; (t = tap->tapno) != 0; ++tap) sum += tap->product[blk[t]]; *out++ = lintomulaw[sum & 0xffff]; ++blk; tap = taps; } } } struct Tap { double val; int tap; }; static int tapCompareV(struct Tap* a, struct Tap* b) { if (a->val > b->val) return (1); return (a->val == b->val? 0 : -1); } static int tapCompareT(struct Tap* a, struct Tap* b) { return (b->tap - a->tap); } void Filter::Create(double *d, int n, int m) { struct Tap wrk[4096]; register int i; for (i = 0; i < n; ++i) { wrk[i].tap = i; wrk[i].val = d[i]; } qsort(wrk, n, sizeof(wrk[0]), (int(*)(const void*, const void*))tapCompareV); qsort(wrk, m, sizeof(wrk[0]), (int(*)(const void*, const void*))tapCompareT); if (taps) delete taps; taps = new FilterTap[m + 1]; ntaps = m; wrk[m].tap = 0; wrk[m].val = 0.; for (i = 0; i <= m; ++i) { taps[i].tapno = -wrk[i].tap; double c = wrk[i].val; taps[i].mod = c >= 0 ? c : -c; for (int u = 0; u < 256; ++u) taps[i].product[u] = (int)(c * (double)mulawtolin[u]); } } static inline void GenerateNoise(u_char *cp, int len) { double phi = 0; double delta = M_PI / len; srandom(u_int(time(0))); while (--len >= 0) { int x = int((random() & (32768 - 1)) - 16384); double cphi = cos(phi); x = (int)((double)x * (1 - cphi * cphi)); phi += delta; *cp++ = lintomulaw[x & 0xffff]; } } static inline void ulawtoreal(u_char *u, double *r, int len) { while (--len >= 0) *r++ = double(mulawtolin[*u++]); } void Filter::Train(int len, int maxtaps) { u_char x[3584], y[3584]; GenerateNoise(x, 3584); int playlen = audio->PlayRec(x, y, sizeof(x)); double rx[sizeof(x)], ry[sizeof(x)]; ulawtoreal(x, rx, playlen); ulawtoreal(y, ry, playlen); Wiener wf(rx, ry, playlen, len); if (maxtaps > len) maxtaps = len; Create(wf.Coeffs(), len, maxtaps); }