/*

  Copyright (C) 2016 Gonzalo José Carracedo Carballal

  This program 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 3 of the
  License, or (at your option) any later version.

  This program 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 program.  If not, see
  <http://www.gnu.org/licenses/>

*/

#ifndef _SIGUTILS_IIR_H
#define _SIGUTILS_IIR_H

#include <stdlib.h>
#include "types.h"

#define SU_FLOAT_GUARD INFINITY

#ifdef __cplusplus
#  ifdef __clang__
#    pragma clang diagnostic push
#    pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#  endif // __clang__
extern "C" {
#endif /* __cplusplus */

/* TODO: Builtin filters */
struct sigutils_iir_filt {
  unsigned int x_size;
  unsigned int y_size;

  unsigned int x_alloc;
  unsigned int y_alloc;

  int x_ptr;
  int y_ptr;

  SUCOMPLEX  curr_y;

  SUCOMPLEX *y;
  SUCOMPLEX *x;

  SUFLOAT *a;
  SUFLOAT *b;

  SUFLOAT gain;
};

typedef struct sigutils_iir_filt su_iir_filt_t;

#define su_iir_filt_INITIALIZER {0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 1}

/* Push sample to filter */
SUCOMPLEX su_iir_filt_feed(su_iir_filt_t *filt, SUCOMPLEX x);

/* Push a bunch of samples to filter */
void su_iir_filt_feed_bulk(
    su_iir_filt_t *filt,
    const SUCOMPLEX *x,
    SUCOMPLEX *y,
    SUSCOUNT len);

/* Get last output */
SUCOMPLEX su_iir_filt_get(const su_iir_filt_t *filt);

/* Initialize filter */
SUBOOL su_iir_filt_init(
    su_iir_filt_t *filt,
    SUSCOUNT y_size,
    const SUFLOAT *a,
    SUSCOUNT x_size,
    const SUFLOAT *b);

/* Initialize filter (internal) */
SUBOOL __su_iir_filt_init(
    su_iir_filt_t *filt,
    SUSCOUNT y_size,
    SUFLOAT *a,
    SUSCOUNT x_size,
    SUFLOAT *b,
    SUBOOL copy_coef);

/* Set output gain */
void su_iir_filt_set_gain(su_iir_filt_t *filt, SUFLOAT gain);

/* Initialize Butterworth low-pass filter of order N */
SUBOOL su_iir_bwlpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc);

/* Initialize Butterworth band-pass filter of order N */
SUBOOL su_iir_bwbpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT f1, SUFLOAT f2);

/* Initialize Root Raised Cosine filter */
SUBOOL su_iir_rrc_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT T, SUFLOAT beta);

/* Initialize Hilbert transform */
SUBOOL su_iir_hilbert_init(su_iir_filt_t *filt, SUSCOUNT n);

/* Initialize brickwall LPF filter */
SUBOOL su_iir_brickwall_lp_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc);

/* Initialize brickwall BPF filter */
SUBOOL su_iir_brickwall_bp_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT bw, SUFLOAT ifnor);

/* Destroy filter */
void su_iir_filt_finalize(su_iir_filt_t *filt);

#ifdef __cplusplus
#  ifdef __clang__
#    pragma clang diagnostic pop
#  endif // __clang__
}
#endif /* __cplusplus */

#endif
