shithub: sox

ref: 914153d3c66a50ad3cc64834ee1f7755cb2eb9d5
dir: /src/earwax.c/

View raw version
/*
 * 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 "sox_i.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 sox_ssample_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 {
  sox_ssample_t *tap; /* taps are z^-1 delays for the FIR filter */
} *earwax_t;

/*
 * Prepare for processing.
 */
static int sox_earwax_start(sox_effect_t * effp)
{
  earwax_t earwax = (earwax_t) effp->priv;
  int i;

  /* check the input format */
  if (effp->ininfo.rate != 44100 || effp->ininfo.channels != 2) {
    sox_fail("The earwax effect works only with 44.1 kHz, stereo audio.");
    return (SOX_EOF);
  }

  /* allocate tap memory */
  earwax->tap = (sox_ssample_t*)xmalloc( sizeof(sox_ssample_t) * EARWAX_NUMTAPS );

  /* zero out the delayed taps */
  for(i=0; i < EARWAX_NUMTAPS; i++ ){
    earwax->tap[i] = 0;
  }

  return (SOX_SUCCESS);
}

/*
 * Processed signed long samples from ibuf to obuf.
 * Return number of samples processed.
 */

static int sox_earwax_flow(sox_effect_t * effp, const sox_ssample_t *ibuf, sox_ssample_t *obuf, 
                   sox_size_t *isamp, sox_size_t *osamp)
{
  earwax_t earwax = (earwax_t) effp->priv;
  int len, done;
  int i;
  sox_ssample_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 (SOX_SUCCESS);
}

/*
 * Drain out taps.
 */
static int sox_earwax_drain(sox_effect_t * effp, sox_ssample_t *obuf, sox_size_t *osamp)
{
  earwax_t earwax = (earwax_t) effp->priv;
  int i,j;
  sox_ssample_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 (SOX_EOF);
}

/*
 * Clean up taps.
 */
static int sox_earwax_stop(sox_effect_t * effp)
{
  earwax_t earwax = (earwax_t) effp->priv;

  free((char *)earwax->tap);

  return (SOX_SUCCESS);
}

static sox_effect_handler_t sox_earwax_effect = {
  "earwax",
  NULL,
  SOX_EFF_MCHAN|SOX_EFF_LENGTH,
  NULL,
  sox_earwax_start,
  sox_earwax_flow,
  sox_earwax_drain,
  sox_earwax_stop,
  NULL
};

const sox_effect_handler_t *sox_earwax_effect_fn(void)
{
    return &sox_earwax_effect;
}