• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <math.h>
22 #include <alsa/asoundlib.h>
23 
24 struct effect_private {
25 	/* filter the sweep variables */
26 	float lfo,dlfo,fs,fc,BW,C,D,a0,a1,a2,b1,b2,*x[3],*y[3];
27 	float lfo_depth, lfo_center;
28 	unsigned int channels;
29 };
30 
effect_init(struct lookback * loopback,void * private_data,snd_pcm_access_t access,unsigned int channels,unsigned int rate,snd_pcm_format_t format)31 static int effect_init(struct lookback *loopback,
32 		       void *private_data,
33 		       snd_pcm_access_t access,
34 		       unsigned int channels,
35 		       unsigned int rate,
36 		       snd_pcm_format_t format)
37 {
38 	struct effect_private *priv = private_data;
39 	int i;
40 
41 #if __BYTE_ORDER == __LITTLE_ENDIAN
42 	if (format != SND_PCM_FORMAT_S16_LE)
43 		return -EIO;
44 #elif __BYTE_ORDER == __BIG_ENDIAN
45 	if (format != SND_PCM_FORMAT_S16_BE)
46 		return -EIO;
47 #else
48 	return -EIO;
49 #endif
50 	priv->fs = (float) rate;
51 	priv->channels = channels;
52 	for (i = 0; i < 3; i++) {
53 		priv->x[i] = calloc(channels * sizeof(float));
54 		priv->y[i] = calloc(channels * sizeof(float));
55 	}
56 	return 0;
57 }
58 
effect_done(struct loopback * loopback,void * private_data)59 static int effect_done(struct loopback *loopback,
60 		       void *private_data)
61 {
62 	struct effect_private *priv = private_data;
63 	int i;
64 
65 	for (i = 0; i < 3; i++) {
66 		free(priv->x[i]);
67 		free(priv->y[i]);
68 	}
69 	return 0;
70 }
71 
effect_apply(struct loopback * loopback,void * private_data,const snd_pcm_channel_area_t * areas,snd_uframes_t offset,snd_uframes_t frames)72 static int effect_apply(struct loopback *loopback,
73 			void *private_data,
74 			const snd_pcm_channel_area_t *areas,
75 			snd_uframes_t offset,
76 			snd_uframes_t frames)
77 {
78 	struct effect_private *priv = private_data;
79 	short *samples = (short*)areas[0].addr + offset*priv->channels;
80 	snd_uframes_t i;
81 
82 	for (i=0; i < frames; i++) {
83 		int chn;
84 
85 		fc = sin(priv->lfo)*priv->lfo_depth+priv->lfo_center;
86 		priv->lfo += priv->dlfo;
87 		if (priv->lfo>2.*M_PI) priv->lfo -= 2.*M_PI;
88 		priv->C = 1./tan(M_PI*priv->BW/priv->fs);
89 		priv->D = 2.*cos(2*M_PI*fc/fs);
90 		priv->a0 = 1./(1.+priv->C);
91 		priv->a1 = 0;
92 		priv->a2 = -priv->a0;
93 		priv->b1 = -priv->C*priv->D*a0;
94 		priv->b2 = (priv->C-1)*priv->a0;
95 
96 		for (chn=0; chn < priv->channels; chn++)
97 		{
98 			priv->x[chn][2] = priv->x[chn][1];
99 			priv->x[chn][1] = priv->x[chn][0];
100 
101 			priv->y[chn][2] = priv->y[chn][1];
102 			priv->y[chn][1] = priv->y[chn][0];
103 
104 			priv->x[chn][0] = samples[i*channels+chn];
105 			priv->y[chn][0] = priv->a0*priv->x[0][chn]
106 				+ priv->a1*priv->x[1][chn] + priv->a2*x[2][chn]
107 				- priv->b1*priv->y[1][chn] - priv->b2*y[2][chn];
108 			samples[i*channels+chn] = priv->y[chn][0];
109 		}
110 	}
111 	return 0;
112 }
113 
effect_init_sweep(void)114 void effect_init_sweep(void)
115 {
116 	struct effect_private *priv;
117 
118 	priv = register_effect(effect_init,
119 			       effect_apply,
120 			       effect_done,
121 			       sizeof(struct effectprivate));
122 	if (priv) {
123 		priv->lfo_center = 2000.;
124 		priv->lfo_depth = 1800.;
125 		priv->lfo_freq = 0.2;
126 		priv->BW = 50;
127 	}
128 }
129