dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / audio / utilities / Fir.cc
blob3aa43366f0b6c9c5b4429d04da437f9900db610e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright (c) 1992-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <memory.h>
30 #include <stddef.h>
31 #include <sys/types.h>
32 #include <Fir.h>
34 extern "C" {
35 char *bcopy(char *, char *, int);
36 char *memmove(char *, char *, int);
39 #define BCOPY(src, dest, num) memmove(dest, src, num)
42 * convolve()
43 * returns the convolution of coef[length] and in_buf[length]:
45 * convolution = coef[0] * in_buf[length - 1] +
46 * coef[1] * in_buf[length - 2] +
47 * ...
48 * coef[length - 1] * in_buf[0]
50 double
51 convolve(
52 double *coefs,
53 double *in_buf,
54 int length)
56 if (length <= 0)
57 return (0.0);
58 else {
59 in_buf += --length;
60 double sum = *coefs * *in_buf;
61 while (length--)
62 sum += *++coefs * *--in_buf;
63 return (sum);
67 void // convert short to double
68 short2double(
69 double *out,
70 short *in,
71 int size)
73 while (size-- > 0)
74 *out++ = (double)*in++;
77 short
78 double2short(double in) // limit double to short
80 if (in <= -32768.0)
81 return (-32768);
82 else if (in >= 32767.0)
83 return (32767);
84 else
85 return ((short)in);
88 void Fir:: // update state with data[size]
89 updateState(
90 double *data,
91 int size)
93 if (size >= order)
94 memcpy(state, data + size - order, order * sizeof (double));
95 else {
96 int old = order - size;
97 BCOPY((char *)(state + size), (char *)state,
98 old * sizeof (double));
99 memcpy(state + order - size, data, size * sizeof (double));
103 void Fir::
104 update_short(
105 short *in,
106 int size)
108 double *in_buf = new double[size];
109 short2double(in_buf, in, size);
110 updateState(in_buf, size);
111 delete in_buf;
114 void Fir::
115 resetState(void) // reset state to all zero
117 for (int i = 0; i < order; i++)
118 state[i] = 0.0;
121 Fir::
122 Fir(void)
126 Fir::
127 Fir(int order_in): order(order_in) // construct Fir object
129 state = new double[order];
130 resetState();
131 coef = new double[order + 1];
132 delay = (order + 1) >> 1; // assuming symmetric FIR
135 Fir::
136 ~Fir() // destruct Fir object
138 delete coef;
139 delete state;
142 int Fir::
143 getOrder(void) // returns filter order
145 return (order);
148 int Fir::
149 getNumCoefs(void) // returns number of filter coefficients
151 return (order + 1);
154 void Fir::
155 putCoef(double *coef_in) // copy coef_in in filter coefficients
157 memcpy(coef, coef_in, (order + 1) * sizeof (double));
160 void Fir::
161 getCoef(double *coef_out) // returns filter coefs in coef_out
163 memcpy(coef_out, coef, (order + 1) * sizeof (double));
166 int Fir:: // filter in[size], and updates the state.
167 filter_noadjust(
168 short *in,
169 int size,
170 short *out)
172 if (size <= 0)
173 return (0);
175 double *in_buf = new double[size];
176 short2double(in_buf, in, size); // convert short input to double
177 int i;
178 int init_size = (size <= order)? size : order;
179 int init_order = order;
180 double *state_ptr = state;
181 short *out_ptr = out;
183 // the first "order" outputs need state in convolution
184 for (i = 1; i <= init_size; i++)
185 *out_ptr++ = double2short(convolve(coef, in_buf, i) +
186 convolve(coef + i, state_ptr++, init_order--));
188 // starting from "order + 1"th output, state is no longer needed
189 state_ptr = in_buf;
190 while (i++ <= size)
191 *out_ptr++ =
192 double2short(convolve(coef, state_ptr++, order + 1));
193 updateState(in_buf, size);
194 delete in_buf;
195 return (out_ptr - out);
198 int Fir::
199 getFlushSize(void)
201 int group_delay = (order + 1) >> 1;
202 return ((delay < group_delay)? group_delay - delay : 0);
205 int Fir::
206 flush(short *out) // zero input response of Fir
208 int num = getFlushSize();
209 if (num > 0) {
210 short *in = new short[num];
211 memset(in, 0, num * sizeof (short));
212 num = filter_noadjust(in, num, out);
213 delete in;
215 return (num);
219 * filter() filters in[size] with filter delay adjusted to 0
221 * All FIR filters introduce a delay of "order" samples between input and
222 * output sequences. Most FIR filters are symmetric filters to keep the
223 * linear phase responses. For those FIR fitlers the group delay is
224 * "(order + 1) / 2". So filter_nodelay adjusts the group delay in the
225 * output sequence such that the output is aligned with the input and
226 * direct comparison between them is possible.
228 * The first call of filter returns "size - group_delay" output samples.
229 * After all the input samples have been filtered, filter() needs
230 * to be called with size = 0 to get the residual output samples to make
231 * the output sequence the same length as the input.
235 int Fir::
236 filter(
237 short *in,
238 int size,
239 short *out)
241 if ((size <= 0) || (in == NULL))
242 return (flush(out));
243 else if (delay <= 0)
244 return (filter_noadjust(in, size, out));
245 else if (size <= delay) {
246 update_short(in, size);
247 delay -= size;
248 return (0);
249 } else {
250 update_short(in, delay);
251 in += delay;
252 size -= delay;
253 delay = 0;
254 return (filter_noadjust(in, size, out));