Sigrid Solveig Haflínudóttirfix warnings6bc6a9b3 years agoHistory
358 lines · 10.0 KB · C
RawDownload
/* noisered - Noise Reduction Effect. * * Written by Ian Turner (vectro@vectro.org) * * Copyright 1999 Ian Turner * This source code is freely redistributable and may be used for * any purpose.  This copyright notice must be maintained. * Authors are not responsible for the consequences of using this software. */ #include "noisered.h" #include <stdlib.h>#include <errno.h>#include <string.h>#include <assert.h> typedef struct {    float *window;    float *lastwindow;    float *noisegate;    float *smoothing;} chandata_t; /* Holds profile information */typedef struct {    char* profile_filename;    float threshold;     chandata_t *chandata;    size_t bufdata;} priv_t; static void FFT(unsigned NumSamples,         int InverseTransform,         const float *RealIn, float *ImagIn, float *RealOut, float *ImagOut){  unsigned i;  double * work = malloc(2 * NumSamples * sizeof(*work));  for (i = 0; i < 2 * NumSamples; i += 2) {    work[i] = RealIn[i >> 1];    work[i + 1] = ImagIn? ImagIn[i >> 1] : 0;  }  lsx_safe_cdft(2 * (int)NumSamples, InverseTransform? -1 : 1, work);  if (InverseTransform) for (i = 0; i < 2 * NumSamples; i += 2) {    RealOut[i >> 1] = work[i] / NumSamples;    ImagOut[i >> 1] = work[i + 1] / NumSamples;  }  else for (i = 0; i < 2 * NumSamples; i += 2) {    RealOut[i >> 1] = work[i];    ImagOut[i >> 1] = work[i + 1];  }  free(work);} /* * Get the options. Default file is stdin (if the audio * input file isn't coming from there, of course!) */static int sox_noisered_getopts(sox_effect_t * effp, int argc, char **argv){  priv_t * p = (priv_t *) effp->priv;  --argc, ++argv;   if (argc > 0) {    p->profile_filename = argv[0];    ++argv;    --argc;  }   p->threshold = 0.5;  do {     /* break-able block */    NUMERIC_PARAMETER(threshold, 0, 1);    USED(argv);  } while (0);   return argc? lsx_usage(effp) : SOX_SUCCESS;} /* * Prepare processing. * Do all initializations. */static int sox_noisered_start(sox_effect_t * effp){    priv_t * data = (priv_t *) effp->priv;    size_t fchannels = 0;    size_t channels = effp->in_signal.channels;    size_t i;    FILE * ifp = lsx_open_input_file(effp, data->profile_filename, sox_false);     if (!ifp)      return SOX_EOF;     data->chandata = lsx_calloc(channels, sizeof(*(data->chandata)));    data->bufdata = 0;    for (i = 0; i < channels; i ++) {        data->chandata[i].noisegate = lsx_calloc(FREQCOUNT, sizeof(float));        data->chandata[i].smoothing = lsx_calloc(FREQCOUNT, sizeof(float));        data->chandata[i].lastwindow = NULL;    }    while (1) {        unsigned long i1_ul;        size_t i1;        float f1;        if (2 != fscanf(ifp, " Channel %lu: %f", &i1_ul, &f1))            break;        i1 = i1_ul;        if (i1 != fchannels) {            lsx_fail("noisered: Got channel %lu, expected channel %lu.",                    (unsigned long)i1, (unsigned long)fchannels);            return SOX_EOF;        }         data->chandata[fchannels].noisegate[0] = f1;        for (i = 1; i < FREQCOUNT; i ++) {            if (1 != fscanf(ifp, ", %f", &f1)) {                lsx_fail("noisered: Not enough data for channel %lu "                        "(expected %d, got %lu)", (unsigned long)fchannels, FREQCOUNT, (unsigned long)i);                return SOX_EOF;            }            data->chandata[fchannels].noisegate[i] = f1;        }        fchannels ++;    }    if (fchannels != channels) {        lsx_fail("noisered: channel mismatch: %lu in input, %lu in profile.",                (unsigned long)channels, (unsigned long)fchannels);        return SOX_EOF;    }    if (ifp != stdin)      fclose(ifp);   effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */     return (SOX_SUCCESS);} /* Mangle a single window. Each output sample (except the first and last * half-window) is the result of two distinct calls to this function, * due to overlapping windows. */static void reduce_noise(chandata_t* chan, float* window, double level){    float *inr, *ini, *outr, *outi, *power;    float *smoothing = chan->smoothing;    int i;     inr = lsx_calloc(WINDOWSIZE * 5, sizeof(float));    ini = inr + WINDOWSIZE;    outr = ini + WINDOWSIZE;    outi = outr + WINDOWSIZE;    power = outi + WINDOWSIZE;     for (i = 0; i < FREQCOUNT; i ++)        assert(smoothing[i] >= 0 && smoothing[i] <= 1);     memcpy(inr, window, WINDOWSIZE*sizeof(float));     FFT(WINDOWSIZE, 0, inr, NULL, outr, outi);     memcpy(inr, window, WINDOWSIZE*sizeof(float));    lsx_apply_hann_f(inr, WINDOWSIZE);    lsx_power_spectrum_f(WINDOWSIZE, inr, power);     for (i = 0; i < FREQCOUNT; i ++) {        float smooth;        float plog;        plog = log(power[i]);        if (power[i] != 0 && plog < chan->noisegate[i] + level*8.0)            smooth = 0.0;        else            smooth = 1.0;         smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5;    }     /* Audacity says this code will eliminate tinkle bells.     * I have no idea what that means. */    for (i = 2; i < FREQCOUNT - 2; i ++) {        if (smoothing[i]>=0.5 &&            smoothing[i]<=0.55 &&            smoothing[i-1]<0.1 &&            smoothing[i-2]<0.1 &&            smoothing[i+1]<0.1 &&            smoothing[i+2]<0.1)            smoothing[i] = 0.0;    }     outr[0] *= smoothing[0];    outi[0] *= smoothing[0];    outr[FREQCOUNT-1] *= smoothing[FREQCOUNT-1];    outi[FREQCOUNT-1] *= smoothing[FREQCOUNT-1];     for (i = 1; i < FREQCOUNT-1; i ++) {        int j = WINDOWSIZE - i;        float smooth = smoothing[i];         outr[i] *= smooth;        outi[i] *= smooth;        outr[j] *= smooth;        outi[j] *= smooth;    }     FFT(WINDOWSIZE, 1, outr, outi, inr, ini);    lsx_apply_hann_f(inr, WINDOWSIZE);     memcpy(window, inr, WINDOWSIZE*sizeof(float));     for (i = 0; i < FREQCOUNT; i ++)        assert(smoothing[i] >= 0 && smoothing[i] <= 1);     free(inr);} /* Do window management once we have a complete window, including mangling * the current window. */static int process_window(sox_effect_t * effp, priv_t * data, unsigned chan_num, unsigned num_chans,                          sox_sample_t *obuf, unsigned len) {    int j;    float* nextwindow;    int use = min(len, WINDOWSIZE)-min(len,(WINDOWSIZE/2));    chandata_t *chan = &(data->chandata[chan_num]);    int first = (chan->lastwindow == NULL);    SOX_SAMPLE_LOCALS;     if ((nextwindow = lsx_calloc(WINDOWSIZE, sizeof(float))) == NULL)        return SOX_EOF;     memcpy(nextwindow, chan->window+WINDOWSIZE/2,           sizeof(float)*(WINDOWSIZE/2));     reduce_noise(chan, chan->window, data->threshold);    if (!first) {        for (j = 0; j < use; j ++) {            float s = chan->window[j] + chan->lastwindow[WINDOWSIZE/2 + j];            obuf[chan_num + num_chans * j] =                SOX_FLOAT_32BIT_TO_SAMPLE(s, effp->clips);        }        free(chan->lastwindow);    } else {        for (j = 0; j < use; j ++) {            assert(chan->window[j] >= -1 && chan->window[j] <= 1);            obuf[chan_num + num_chans * j] =                SOX_FLOAT_32BIT_TO_SAMPLE(chan->window[j], effp->clips);        }    }    chan->lastwindow = chan->window;    chan->window = nextwindow;     return use;} /* * Read in windows, and call process_window once we get a whole one. */static int sox_noisered_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,                    size_t *isamp, size_t *osamp){    priv_t * data = (priv_t *) effp->priv;    size_t samp = min(*isamp, *osamp);    size_t tracks = effp->in_signal.channels;    size_t track_samples = samp / tracks;    size_t ncopy = min(track_samples, WINDOWSIZE-data->bufdata);    size_t whole_window = (ncopy + data->bufdata == WINDOWSIZE);    int oldbuf = data->bufdata;    size_t i;     /* FIXME: Make this automatic for all effects */    assert(effp->in_signal.channels == effp->out_signal.channels);     if (whole_window)        data->bufdata = WINDOWSIZE/2;    else        data->bufdata += ncopy;     /* Reduce noise on every channel. */    for (i = 0; i < tracks; i ++) {        SOX_SAMPLE_LOCALS;        chandata_t* chan = &(data->chandata[i]);        size_t j;         if (chan->window == NULL)            chan->window = lsx_calloc(WINDOWSIZE, sizeof(float));         for (j = 0; j < ncopy; j ++)            chan->window[oldbuf + j] =                SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + tracks * j], effp->clips);         if (!whole_window)            continue;        else            process_window(effp, data, (unsigned) i, (unsigned) tracks, obuf, (unsigned) (oldbuf + ncopy));    }     *isamp = tracks*ncopy;    if (whole_window)        *osamp = tracks*(WINDOWSIZE/2);    else        *osamp = 0;     return SOX_SUCCESS;} /* * We have up to half a window left to dump. */ static int sox_noisered_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp){    priv_t * data = (priv_t *)effp->priv;    unsigned i;    unsigned tracks = effp->in_signal.channels;    for (i = 0; i < tracks; i ++)        *osamp = process_window(effp, data, i, tracks, obuf, (unsigned) data->bufdata);     /* FIXME: This is very picky.  osamp needs to be big enough to get all     * remaining data or it will be discarded.     */    return (SOX_EOF);} /* * Clean up. */static int sox_noisered_stop(sox_effect_t * effp){    priv_t * data = (priv_t *) effp->priv;    size_t i;     for (i = 0; i < effp->in_signal.channels; i ++) {        chandata_t* chan = &(data->chandata[i]);        free(chan->lastwindow);        free(chan->window);        free(chan->smoothing);        free(chan->noisegate);    }     free(data->chandata);     return (SOX_SUCCESS);} static sox_effect_handler_t sox_noisered_effect = {  "noisered",  "[profile-file [amount]]",  SOX_EFF_MCHAN|SOX_EFF_LENGTH,  sox_noisered_getopts,  sox_noisered_start,  sox_noisered_flow,  sox_noisered_drain,  sox_noisered_stop,  NULL, sizeof(priv_t)}; const sox_effect_handler_t *lsx_noisered_effect_fn(void){    return &sox_noisered_effect;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t