root/modules/audio_filter/audio_filter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ProcessDistorsion
  2. ProcessIdentity
  3. ProcessDelai
  4. Configure
  5. SetFilter
  6. SetOption
  7. Reset
  8. NewAudioFilter
  9. DeleteAudioFilter
  10. QueryInterfaces
  11. LoadInterface
  12. ShutdownInterface

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                              Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2010-2012
 *                                      All rights reserved
 *
 *
 *  This file is part of GPAC / sample audio filter module
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#include <gpac/modules/audio_out.h>
#include <gpac/maths.h>

#ifndef PI
#define PI GF_PI
#endif

typedef struct
{
        u32 type;
        Bool inplace;
        u32 sample_block_size;

        /*distorsion param*/
        Double gain, clip, volume;

        /*delai param*/
        char *delai_buffer, *block_buffer;
        u32 delai_ms, delai_buffer_size, block_size, nb_bytes;
        Double feedback;
} FilterContext;

static GF_Err ProcessDistorsion(GF_AudioFilter *af, void *in_block, u32 in_block_size, void *out_block, u32 *out_block_size)
{
        u32 i, count;
        register Double temp;
        Double gain, clip, volume;
        FilterContext *ctx = (FilterContext*)af->udta;

        gain=ctx->gain / 100.0;
        clip=ctx->clip * 32768.0 / 100.0;
        volume=ctx->volume / 100.0;
        count = in_block_size>>1;
        for(i=0; i<count; i++) {
                temp = (Double) ((s16 *) in_block)[i];
                temp = temp * gain;

                if (temp > clip) temp = clip;
                else if (temp < -clip) temp = -clip;
                temp = temp*volume;

                if (temp > 32767.0) temp = 32767.0;
                else if (temp < -32768.0) temp = -32768.0;
                ((s16 *) out_block)[i] = (s16) temp;
        }
        *out_block_size = in_block_size;
        return GF_OK;
}

static GF_Err ProcessIdentity(GF_AudioFilter *af, void *in_block, u32 in_block_size, void *out_block, u32 *out_block_size)
{
        FilterContext *ctx = (FilterContext*)af->udta;
        if (!ctx->inplace)
                memcpy(out_block, in_block, in_block_size);

        *out_block_size = in_block_size;
        return GF_OK;
}

static GF_Err ProcessDelai(GF_AudioFilter *af, void *in_block, u32 in_block_size, void *out_block, u32 *out_block_size)
{
        s16 *in, *delay, *out;
        u32 i;
        register Double temp;
        Double ratio, vol;
        FilterContext *ctx = (FilterContext*)af->udta;
        assert(ctx->block_size==in_block_size);

        /*fill delai buffer*/
        if (ctx->nb_bytes<ctx->delai_buffer_size) {
                memcpy(ctx->delai_buffer + ctx->nb_bytes, in_block, in_block_size);
                ctx->nb_bytes += in_block_size;
                memcpy(out_block, in_block, in_block_size);
                *out_block_size = in_block_size;
                return GF_OK;
        }
        memcpy(ctx->block_buffer, ctx->delai_buffer, ctx->block_size);
        memmove(ctx->delai_buffer, ctx->delai_buffer + ctx->block_size, (ctx->delai_buffer_size-ctx->block_size) );

        vol = ctx->volume / 100;
        ratio = ctx->feedback/100;
        delay = (s16 *) ctx->block_buffer;
        in = (s16 *) in_block;
        out = (s16 *) out_block;
        for (i=0; i<ctx->block_size/2; i++) {
                temp = (1-ratio)*in[i] + ratio*delay[i];
                temp = temp*vol;
                out[i] = (s16) temp;
        }
        memcpy(ctx->delai_buffer + ctx->nb_bytes - in_block_size, out_block, in_block_size);

        *out_block_size = ctx->block_size;
        return GF_OK;
}


static GF_Err Configure(GF_AudioFilter *af, u32 in_sr, u32 in_bps, u32 in_nb_ch, u32 in_ch_cfg, u32 *out_nb_ch, u32 *out_ch_cfg, u32 *out_block_len_in_samples, u32 *delay_ms, Bool *inplace)
{
        FilterContext *ctx = (FilterContext*)af->udta;

        *inplace = ctx->inplace;
        *delay_ms = 0;
        *out_nb_ch = in_nb_ch;
        *out_ch_cfg = in_ch_cfg;

        switch (ctx->type) {
        case 2:
                ctx->block_size = ctx->sample_block_size * in_nb_ch * in_bps / 8;
                ctx->delai_buffer_size = in_nb_ch * in_bps * ctx->delai_ms * in_sr / 1000 / 8;
                ctx->delai_buffer_size /= ctx->block_size;
                ctx->delai_buffer_size *= ctx->block_size;

                if (ctx->delai_buffer) gf_free(ctx->delai_buffer);
                ctx->delai_buffer = (char*)gf_malloc(sizeof(char)*ctx->delai_buffer_size);
                memset(ctx->delai_buffer, 0, sizeof(char)*ctx->delai_buffer_size);

                if (ctx->block_buffer) gf_free(ctx->block_buffer);
                ctx->block_buffer = (char*)gf_malloc(sizeof(char)*ctx->block_size);
                memset(ctx->block_buffer, 0, sizeof(char)*ctx->block_size);
                break;
        }

        *out_block_len_in_samples = ctx->sample_block_size;
        return GF_OK;
}

static Bool SetFilter(GF_AudioFilter *af, char *filter)
{
        char *opts;
        FilterContext *ctx = (FilterContext*)af->udta;
        if (!filter) return GF_FALSE;

        opts = strchr(filter, '@');
        if (opts) opts[0] = 0;

        ctx->sample_block_size = 0;
        ctx->inplace = GF_TRUE;
        ctx->volume = 100.0;

        if (!stricmp(filter, "identity")) {
                af->Process = ProcessIdentity;
                ctx->type = 0;
        }
        else if (!stricmp(filter, "distorsion")) {
                ctx->gain=50.0;
                ctx->clip=100.0;
                af->Process = ProcessDistorsion;
                ctx->type = 1;
        }
        else if (!stricmp(filter, "delai")) {
                ctx->delai_ms = 100;
                ctx->feedback = 50;
                af->Process = ProcessDelai;
                ctx->type = 2;
                ctx->sample_block_size = 120;
        } else {
                if (opts) opts[0] = '@';
                return GF_FALSE;
        }
        if (opts) {
                opts[0] = '@';
                opts++;

                while (1) {
                        char *sep = strchr(opts, ';');
                        if (sep) sep[0] = 0;

                        if (!strnicmp(opts, "blocksize=", 10)) ctx->sample_block_size = atoi(opts+10);
                        else if (!stricmp(opts, "noinplace")) ctx->inplace = GF_FALSE;
                        else if (!strnicmp(opts, "gain=", 5)) ctx->gain = atof(opts+5);
                        else if (!strnicmp(opts, "clip=", 5)) ctx->clip = atof(opts+5);
                        else if (!strnicmp(opts, "volume=", 7)) ctx->volume = atof(opts+7);
                        else if (!strnicmp(opts, "delai=", 6)) ctx->delai_ms = atoi(opts+6);
                        else if (!strnicmp(opts, "feedback=", 9)) {
                                ctx->feedback = atof(opts+9);
                                if (ctx->feedback>100) ctx->feedback=100;
                        }

                        if (!sep) break;
                        sep[0] = ';';
                        opts = sep+1;
                }
        }

        return GF_TRUE;
}


static Bool SetOption(GF_AudioFilter *af, char *option, char *value)
{
        return GF_TRUE;
}
static void Reset(GF_AudioFilter *af)
{
}


GF_BaseInterface *NewAudioFilter()
{
        FilterContext *ctx;
        GF_AudioFilter *mod;
        GF_SAFEALLOC(ctx, FilterContext);
        if(!ctx) return NULL;

        GF_SAFEALLOC(mod, GF_AudioFilter);
        if(!mod) {
                gf_free(ctx);
                return NULL;
        }
        mod->udta = ctx;
        mod->SetFilter = SetFilter;
        mod->Configure = Configure;
        mod->Process = ProcessIdentity;
        mod->SetOption = SetOption;
        mod->Reset = Reset;

        GF_REGISTER_MODULE_INTERFACE(mod, GF_AUDIO_FILTER_INTERFACE, "Sample Audio Filter", "gpac distribution");
        return (GF_BaseInterface*)mod;
}

void DeleteAudioFilter(void *ifce)
{
        GF_AudioFilter *dr = (GF_AudioFilter*) ifce;
        FilterContext *ctx = (FilterContext *)dr->udta;

        if (ctx->delai_buffer) gf_free(ctx->delai_buffer);
        gf_free(ctx);
        gf_free(dr);
}


/*
 * ********************************************************************
 * interface
 */
GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
        static u32 si [] = {
                GF_AUDIO_FILTER_INTERFACE,
                0
        };
        return si;
}

GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
        if (InterfaceType == GF_AUDIO_FILTER_INTERFACE)
                return NewAudioFilter();
        return NULL;
}

GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *ifce)
{
        if (ifce->InterfaceType==GF_AUDIO_FILTER_INTERFACE)
                DeleteAudioFilter((GF_AudioFilter*)ifce);
}

GPAC_MODULE_STATIC_DECLARATION( audio_filter )

/* [<][>][^][v][top][bottom][index][help] */