ref: b5db60e89ae731cf22f7405722353b06d9b8977f
dir: /src/earwax.c/
/* * 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. */ /* * 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) * */ #include "st.h" #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 LONG 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 { LONG *tap; /* taps are z^-1 delays for the FIR filter */ } *earwax_t; /* * Process options */ int st_earwax_getopts(effp, n, argv) eff_t effp; int n; char **argv; { /* no options */ if (n){ st_fail("The earwax filtering effect takes no options.\n"); return (ST_EOF); } return (ST_SUCCESS); } /* * Prepare for processing. */ int st_earwax_start(effp) eff_t effp; { earwax_t earwax = (earwax_t) effp->priv; int i; /* check the input format */ if (effp->ininfo.encoding != ST_ENCODING_SIGN2 || effp->ininfo.rate != 44100 || effp->ininfo.channels != 2){ st_fail("the earwax effect works only with audio cd (44.1 kHz, twos-complement signed linear, stereo) samples.\n"); return (ST_EOF); } /* allocate tap memory */ earwax->tap = (LONG*)malloc( sizeof(LONG) * EARWAX_NUMTAPS ); if( !earwax->tap ){ st_fail("earwax: Cannot malloc %d bytes!\n", sizeof(LONG) * EARWAX_NUMTAPS ); return (ST_EOF); } /* 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. */ int st_earwax_flow(effp, ibuf, obuf, isamp, osamp) eff_t effp; LONG *ibuf, *obuf; LONG *isamp, *osamp; { earwax_t earwax = (earwax_t) effp->priv; int len, done; int i; LONG 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. */ int st_earwax_drain(effp, obuf, osamp) eff_t effp; LONG *obuf; LONG *osamp; { earwax_t earwax = (earwax_t) effp->priv; int i,j; LONG 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_SUCCESS); } /* * Clean up taps. */ int st_earwax_stop(effp) eff_t effp; { earwax_t earwax = (earwax_t) effp->priv; free((char *)earwax->tap); return (ST_SUCCESS); }