1 /*
2 * Bandpass filter sweep effect
3 * Copyright (c) Maarten de Boer <mdeboer@iua.upf.es>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include "aconfig.h"
22 #include <math.h>
23 #include <alsa/asoundlib.h>
24
25 struct effect_private {
26 /* filter the sweep variables */
27 float lfo,dlfo,fs,fc,BW,C,D,a0,a1,a2,b1,b2,*x[3],*y[3];
28 float lfo_depth, lfo_center;
29 unsigned int channels;
30 };
31
effect_init(struct lookback * loopback,void * private_data,snd_pcm_access_t access,unsigned int channels,unsigned int rate,snd_pcm_format_t format)32 static int effect_init(struct lookback *loopback,
33 void *private_data,
34 snd_pcm_access_t access,
35 unsigned int channels,
36 unsigned int rate,
37 snd_pcm_format_t format)
38 {
39 struct effect_private *priv = private_data;
40 int i;
41
42 #if __BYTE_ORDER == __LITTLE_ENDIAN
43 if (format != SND_PCM_FORMAT_S16_LE)
44 return -EIO;
45 #elif __BYTE_ORDER == __BIG_ENDIAN
46 if (format != SND_PCM_FORMAT_S16_BE)
47 return -EIO;
48 #else
49 return -EIO;
50 #endif
51 priv->fs = (float) rate;
52 priv->channels = channels;
53 for (i = 0; i < 3; i++) {
54 priv->x[i] = calloc(channels * sizeof(float));
55 priv->y[i] = calloc(channels * sizeof(float));
56 }
57 return 0;
58 }
59
effect_done(struct loopback * loopback,void * private_data)60 static int effect_done(struct loopback *loopback,
61 void *private_data)
62 {
63 struct effect_private *priv = private_data;
64 int i;
65
66 for (i = 0; i < 3; i++) {
67 free(priv->x[i]);
68 free(priv->y[i]);
69 }
70 return 0;
71 }
72
effect_apply(struct loopback * loopback,void * private_data,const snd_pcm_channel_area_t * areas,snd_uframes_t offset,snd_uframes_t frames)73 static int effect_apply(struct loopback *loopback,
74 void *private_data,
75 const snd_pcm_channel_area_t *areas,
76 snd_uframes_t offset,
77 snd_uframes_t frames)
78 {
79 struct effect_private *priv = private_data;
80 short *samples = (short*)areas[0].addr + offset*priv->channels;
81 snd_uframes_t i;
82
83 for (i=0; i < frames; i++) {
84 int chn;
85
86 fc = sin(priv->lfo)*priv->lfo_depth+priv->lfo_center;
87 priv->lfo += priv->dlfo;
88 if (priv->lfo>2.*M_PI) priv->lfo -= 2.*M_PI;
89 priv->C = 1./tan(M_PI*priv->BW/priv->fs);
90 priv->D = 2.*cos(2*M_PI*fc/fs);
91 priv->a0 = 1./(1.+priv->C);
92 priv->a1 = 0;
93 priv->a2 = -priv->a0;
94 priv->b1 = -priv->C*priv->D*a0;
95 priv->b2 = (priv->C-1)*priv->a0;
96
97 for (chn=0; chn < priv->channels; chn++)
98 {
99 priv->x[chn][2] = priv->x[chn][1];
100 priv->x[chn][1] = priv->x[chn][0];
101
102 priv->y[chn][2] = priv->y[chn][1];
103 priv->y[chn][1] = priv->y[chn][0];
104
105 priv->x[chn][0] = samples[i*channels+chn];
106 priv->y[chn][0] = priv->a0*priv->x[0][chn]
107 + priv->a1*priv->x[1][chn] + priv->a2*x[2][chn]
108 - priv->b1*priv->y[1][chn] - priv->b2*y[2][chn];
109 samples[i*channels+chn] = priv->y[chn][0];
110 }
111 }
112 return 0;
113 }
114
effect_init_sweep(void)115 void effect_init_sweep(void)
116 {
117 struct effect_private *priv;
118
119 priv = register_effect(effect_init,
120 effect_apply,
121 effect_done,
122 sizeof(struct effectprivate));
123 if (priv) {
124 priv->lfo_center = 2000.;
125 priv->lfo_depth = 1800.;
126 priv->lfo_freq = 0.2;
127 priv->BW = 50;
128 }
129 }
130