• 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 "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