ref: cb3887225cee68ff4575fb2de1cc8c67e5f96a74
dir: /src/earwax.c/
/*
* earwax - makes listening to headphones easier
*
* This effect takes a stereo sound that is meant to be listened to
* on headphones, and adds audio cues to move the soundstage from inside
* your head (standard for headphones) to outside and in front of the
* listener (standard for speakers). This makes the sound much easier to
* listen to on headphones. See www.geocities.com/beinges for a full
* explanation.
*
* Usage:
* earwax
*
* Note:
* This filter only works for 44.1 kHz stereo signals (cd format)
*
* November 9, 2000
* Copyright (C) 2000 Edward Beingessner And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Edward Beingessner And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
#include "st_i.h"
static st_effect_t st_earwax_effect;
#define EARWAX_SCALE 64
/* A stereo fir filter. One side filters as if the signal was from
30 degrees from the ear, the other as if 330 degrees. */
/* 30 330 */
static const st_sample_t filt[] =
{ 4, -6,
4, -11,
-1, -5,
3, 3,
-2, 5,
-5, 0,
9, 1,
6, 3,
-4, -1,
-5, -3,
-2, -5,
-7, 1,
6, -7,
30, -29,
12, -3,
-11, 4,
-3, 7,
-20, 23,
2, 0,
1, -6,
-14, -5,
15, -18,
6, 7,
15, -10,
-14, 22,
-7, -2,
-4, 9,
6, -12,
6, -6,
0, -11,
0, -5,
4, 0};
/* 32 tap stereo FIR filter needs 64 taps */
#define EARWAX_NUMTAPS 64
typedef struct earwaxstuff {
st_sample_t *tap; /* taps are z^-1 delays for the FIR filter */
} *earwax_t;
/*
* Prepare for processing.
*/
static int st_earwax_start(eff_t effp)
{
earwax_t earwax = (earwax_t) effp->priv;
int i;
/* check the input format */
if (effp->ininfo.rate != 44100 || effp->ininfo.channels != 2) {
st_fail("The earwax effect works only with 44.1 kHz, stereo audio.");
return (ST_EOF);
}
/* allocate tap memory */
earwax->tap = (st_sample_t*)xmalloc( sizeof(st_sample_t) * EARWAX_NUMTAPS );
/* zero out the delayed taps */
for(i=0; i < EARWAX_NUMTAPS; i++ ){
earwax->tap[i] = 0;
}
return (ST_SUCCESS);
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
static int st_earwax_flow(eff_t effp, const st_sample_t *ibuf, st_sample_t *obuf,
st_size_t *isamp, st_size_t *osamp)
{
earwax_t earwax = (earwax_t) effp->priv;
int len, done;
int i;
st_sample_t output;
len = ((*isamp > *osamp) ? *osamp : *isamp);
for(done = 0; done < len; done++) {
/* update taps and calculate output */
output = 0;
for(i = EARWAX_NUMTAPS-1; i > 0; i--) {
earwax->tap[i] = earwax->tap[i-1];
output += earwax->tap[i] * filt[i];
}
earwax->tap[0] = *ibuf++ / EARWAX_SCALE;
output += earwax->tap[0] * filt[i];
/* store scaled output */
*obuf++ = output;
}
*isamp = *osamp = len;
return (ST_SUCCESS);
}
/*
* Drain out taps.
*/
static int st_earwax_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp)
{
earwax_t earwax = (earwax_t) effp->priv;
int i,j;
st_sample_t output;
for(i = EARWAX_NUMTAPS-1; i >= 0; i--){
output = 0;
for(j = 0; j < i; j++ ){
output += filt[j+(EARWAX_NUMTAPS-i)] * earwax->tap[j];
}
*obuf++ = output;
}
*osamp = EARWAX_NUMTAPS-1;
return (ST_EOF);
}
/*
* Clean up taps.
*/
static int st_earwax_stop(eff_t effp)
{
earwax_t earwax = (earwax_t) effp->priv;
free((char *)earwax->tap);
return (ST_SUCCESS);
}
static st_effect_t st_earwax_effect = {
"earwax",
"Usage: The earwax filtering effect takes no options",
ST_EFF_MCHAN,
st_effect_nothing_getopts,
st_earwax_start,
st_earwax_flow,
st_earwax_drain,
st_earwax_stop,
st_effect_nothing
};
const st_effect_t *st_earwax_effect_fn(void)
{
return &st_earwax_effect;
}