ref: d3f0b58897fb47913449b7489c2cef7ab9d0f510
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_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; /* * Process options */ int st_earwax_getopts(eff_t effp, int n, char **argv) { /* no options */ if (n){ st_fail(st_earwax_effect.usage); return (ST_EOF); } return (ST_SUCCESS); } /* * Prepare for processing. */ int st_earwax_start(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 = (st_sample_t*)malloc( sizeof(st_sample_t) * EARWAX_NUMTAPS ); if( !earwax->tap ){ st_fail("earwax: Cannot malloc %d bytes!\n", sizeof(st_sample_t) * 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(eff_t effp, 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. */ 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. */ 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_earwax_getopts, st_earwax_start, st_earwax_flow, st_earwax_drain, st_earwax_stop }; const st_effect_t *st_earwax_effect_fn(void) { return &st_earwax_effect; }