mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-23 09:46:31 +01:00
b1e3d945b7
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
128 lines
3.3 KiB
C
128 lines
3.3 KiB
C
/*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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;
|
|
}
|
|
}
|