···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/filter.c *
77+ * Created: 2010-08-27 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2010 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#include <config.h>
2424+2525+#include <stdint.h>
2626+#include <math.h>
2727+2828+#include <drivers/sound/filter.h>
2929+3030+3131+#define SND_IIR_MUL 8192
3232+3333+3434+void snd_iir2_init (sound_iir2_t *iir)
3535+{
3636+ unsigned i;
3737+3838+ for (i = 0; i < 3; i++) {
3939+ iir->a[i] = 0;
4040+ iir->b[i] = 0;
4141+ iir->x[i] = 0;
4242+ iir->y[i] = 0;
4343+ }
4444+4545+ iir->a[0] = SND_IIR_MUL;
4646+}
4747+4848+void snd_iir2_reset (sound_iir2_t *iir)
4949+{
5050+ iir->x[0] = 0;
5151+ iir->x[1] = 0;
5252+ iir->x[2] = 0;
5353+5454+ iir->y[0] = 0;
5555+ iir->y[1] = 0;
5656+ iir->y[2] = 0;
5757+}
5858+5959+void snd_iir2_set_lowpass (sound_iir2_t *iir, unsigned long freq, unsigned long srate)
6060+{
6161+ double om, b0;
6262+6363+ snd_iir2_init (iir);
6464+6565+ if ((freq == 0) || (srate == 0)) {
6666+ return;
6767+ }
6868+6969+ if ((2 * freq) >= srate) {
7070+ freq = (srate / 2) - 1;
7171+ }
7272+7373+ om = 1.0 / tan ((3.14159265358979312 * freq) / srate);
7474+ b0 = om * (om + sqrt(2.0)) + 1.0;
7575+7676+ iir->a[0] = (long) (SND_IIR_MUL * 1.0 / b0);
7777+ iir->a[1] = (long) (SND_IIR_MUL * 2.0 / b0);
7878+ iir->a[2] = (long) (SND_IIR_MUL * 1.0 / b0);
7979+8080+ iir->b[0] = (long) (SND_IIR_MUL * 1.0);
8181+ iir->b[1] = (long) (SND_IIR_MUL * 2.0 * (1.0 - om * om) / b0);
8282+ iir->b[2] = (long) (SND_IIR_MUL * (om * (om - sqrt(2.0)) + 1.0) / b0);
8383+}
8484+8585+void snd_iir2_filter (sound_iir2_t *iir, uint16_t *dst, const uint16_t *src,
8686+ unsigned cnt, unsigned ofs, int sign)
8787+{
8888+ long v;
8989+ uint16_t sig;
9090+9191+ sig = sign ? 0x8000 : 0;
9292+9393+ while (cnt > 0) {
9494+ v = *src ^ sig;
9595+ v -= 32768;
9696+9797+ iir->x[2] = iir->x[1];
9898+ iir->x[1] = iir->x[0];
9999+ iir->x[0] = v;
100100+101101+ iir->y[2] = iir->y[1];
102102+ iir->y[1] = iir->y[0];
103103+104104+ iir->y[0] = iir->a[0] * iir->x[0];
105105+ iir->y[0] += iir->a[1] * iir->x[1] + iir->a[2] * iir->x[2];
106106+ iir->y[0] -= iir->b[1] * iir->y[1] + iir->b[2] * iir->y[2];
107107+108108+ iir->y[0] = iir->y[0] / SND_IIR_MUL;
109109+110110+ v = iir->y[0];
111111+ v += 32768;
112112+113113+ if (v < 0) {
114114+ v = 0;
115115+ }
116116+ else if (v > 65535) {
117117+ v = 0xffff;
118118+ }
119119+ else {
120120+ v &= 0xffff;
121121+ }
122122+123123+ *dst = ((uint16_t) v) ^ sig;
124124+125125+ src += ofs;
126126+ dst += ofs;
127127+ cnt -= 1;
128128+ }
129129+}
+75
src/drivers/sound/filter.h
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound.h *
77+ * Created: 2010-08-27 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2010 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#ifndef PCE_DRIVERS_SOUND_FILTER_H
2424+#define PCE_DRIVERS_SOUND_FILTER_H 1
2525+2626+2727+#include <stdint.h>
2828+2929+3030+/*!***************************************************************************
3131+ * @short A second order IIR filter
3232+ *****************************************************************************/
3333+typedef struct {
3434+ long a[3];
3535+ long b[3];
3636+ long x[3];
3737+ long y[3];
3838+} sound_iir2_t;
3939+4040+4141+/*!***************************************************************************
4242+ * @short Initialize an IIR2 filter
4343+ *****************************************************************************/
4444+void snd_iir2_init (sound_iir2_t *iir);
4545+4646+/*!***************************************************************************
4747+ * @short Reset an IIR2 filter
4848+ *****************************************************************************/
4949+void snd_iir2_reset (sound_iir2_t *iir);
5050+5151+/*!***************************************************************************
5252+ * @short Initialize a low-pass IIR filter
5353+ * @param freq The cut-off frequency
5454+ * @param srate The sample rate
5555+ *****************************************************************************/
5656+void snd_iir2_set_lowpass (sound_iir2_t *iir,
5757+ unsigned long freq, unsigned long srate
5858+);
5959+6060+/*!***************************************************************************
6161+ * @short Filter samples with an IIR2 filter
6262+ * @param dst The destination buffer
6363+ * @param src The source buffer
6464+ * @param cnt The sample count
6565+ * @param ofs The sample offset in both src and dst
6666+ * @param sign The sample signedness in both src and dst
6767+ *
6868+ * The source and destination buffer can be the same.
6969+ *****************************************************************************/
7070+void snd_iir2_filter (sound_iir2_t *iir,
7171+ uint16_t *dst, const uint16_t *src, unsigned cnt, unsigned ofs, int sign
7272+);
7373+7474+7575+#endif