summaryrefslogtreecommitdiff
path: root/alsaloop/effect-sweep.c
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-08-18 08:29:03 +0200
committerJaroslav Kysela <perex@perex.cz>2010-10-06 10:01:52 +0200
commit1e75673035ffc0971719974715211d6a0a48e61a (patch)
tree1c736c15d0a92d8889b3ae6b7839dafbc7714662 /alsaloop/effect-sweep.c
parent87c58b59b5c443fe3244bd06417c451581d1f635 (diff)
downloadalsa-utils-1e75673035ffc0971719974715211d6a0a48e61a.tar.gz
Introduce alsaloop utility
alsaloop allows create a PCM loopback between a PCM capture device and a PCM playback device. alsaloop supports multiple soundcards, adaptive clock synchronization, adaptive rate resampling using the samplerate library (if available in the system). Also, mixer controls can be redirected from one card to another (for example Master and PCM). Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'alsaloop/effect-sweep.c')
-rw-r--r--alsaloop/effect-sweep.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/alsaloop/effect-sweep.c b/alsaloop/effect-sweep.c
new file mode 100644
index 0000000..4a0903d
--- /dev/null
+++ b/alsaloop/effect-sweep.c
@@ -0,0 +1,128 @@
+/*
+ * Bandpass filter sweep effect
+ * Copyright (c) Maarten de Boer <mdeboer@iua.upf.es>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <math.h>
+#include <alsa/asoundlib.h>
+
+struct effect_private {
+ /* filter the sweep variables */
+ float lfo,dlfo,fs,fc,BW,C,D,a0,a1,a2,b1,b2,*x[3],*y[3];
+ float lfo_depth, lfo_center;
+ unsigned int channels;
+};
+
+static int effect_init(struct lookback *loopback,
+ void *private_data,
+ snd_pcm_access_t access,
+ unsigned int channels,
+ unsigned int rate,
+ snd_pcm_format_t format)
+{
+ struct effect_private *priv = private_data;
+ int i;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if (format != SND_PCM_FORMAT_S16_LE)
+ return -EIO;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ if (format != SND_PCM_FORMAT_S16_BE)
+ return -EIO;
+#else
+ return -EIO;
+#endif
+ priv->fs = (float) rate;
+ priv->channels = channels;
+ for (i = 0; i < 3; i++) {
+ priv->x[i] = calloc(channels * sizeof(float));
+ priv->y[i] = calloc(channels * sizeof(float));
+ }
+ return 0;
+}
+
+static int effect_done(struct loopback *loopback,
+ void *private_data)
+{
+ struct effect_private *priv = private_data;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ free(priv->x[i]);
+ free(priv->y[i]);
+ }
+ return 0;
+}
+
+static int effect_apply(struct loopback *loopback,
+ void *private_data,
+ const snd_pcm_channel_area_t *areas,
+ snd_uframes_t offset,
+ snd_uframes_t frames)
+{
+ struct effect_private *priv = private_data;
+ short *samples = (short*)areas[0].addr + offset*priv->channels;
+ snd_uframes_t i;
+
+ for (i=0; i < frames; i++) {
+ int chn;
+
+ fc = sin(priv->lfo)*priv->lfo_depth+priv->lfo_center;
+ priv->lfo += priv->dlfo;
+ if (priv->lfo>2.*M_PI) priv->lfo -= 2.*M_PI;
+ priv->C = 1./tan(M_PI*priv->BW/priv->fs);
+ priv->D = 2.*cos(2*M_PI*fc/fs);
+ priv->a0 = 1./(1.+priv->C);
+ priv->a1 = 0;
+ priv->a2 = -priv->a0;
+ priv->b1 = -priv->C*priv->D*a0;
+ priv->b2 = (priv->C-1)*priv->a0;
+
+ for (chn=0; chn < priv->channels; chn++)
+ {
+ priv->x[chn][2] = priv->x[chn][1];
+ priv->x[chn][1] = priv->x[chn][0];
+
+ priv->y[chn][2] = priv->y[chn][1];
+ priv->y[chn][1] = priv->y[chn][0];
+
+ priv->x[chn][0] = samples[i*channels+chn];
+ priv->y[chn][0] = priv->a0*priv->x[0][chn]
+ + priv->a1*priv->x[1][chn] + priv->a2*x[2][chn]
+ - priv->b1*priv->y[1][chn] - priv->b2*y[2][chn];
+ samples[i*channels+chn] = priv->y[chn][0];
+ }
+ }
+ return 0;
+}
+
+void effect_init_sweep(void)
+{
+ struct effect_private *priv;
+
+ priv = register_effect(effect_init,
+ effect_apply,
+ effect_done,
+ sizeof(struct effectprivate));
+ if (priv) {
+ priv->lfo_center = 2000.;
+ priv->lfo_depth = 1800.;
+ priv->lfo_freq = 0.2;
+ priv->BW = 50;
+ }
+}