/*
 *  Copyright 1994-2022 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __BINIOU_INPUT_H
#define __BINIOU_INPUT_H

#include <fftw3.h>
#include "utils.h"
#ifdef DEBUG
#include "btimer.h"
#endif
#include "buffer_8bits.h"

/* A_STEREO is only used in calls to Input_set() */
enum Channel { A_MONO=0, A_LEFT=1, A_RIGHT=2, A_STEREO };


typedef struct Input_s {
  /* mutex */
  pthread_mutex_t mutex;

  /* FFTW stuff */
  fftw_plan plan_fft[3];

  /* input buffer size */
  // FIXME make this a uint16_t
  uint32_t size;
  uint32_t size2; /* number of samples in data2 */

  /* to get Mytho Random Numbers(c)(r)(tm) */
  // FIXME make this a uint16_t
  uint32_t roulette;

  /* you can also mute the input  */
  uint8_t   mute;

  /* Write raw input data here then call Input_set(...) */
  /* the input data, [-1..1] */
  double *data[3];
  /* all frames after last context_run
     If plugin can handle variable size input, this should be used instead
     of data. Variable size includes zero size. */
  double *data2[3];

  /*
   * these should be seen as Read-Only
   */
  /* unsigned input, used for PRNGs */
  double *data_u[3];

  /* spectrum info */
  // FIXME make this a uint16_t
  uint32_t spectrum_size;

  /* used to compute FFT */
  fftw_complex *out[3];

  double *spectrum[3];
  double *spectrum_log[3];

  double max_spectrum[3];
  double max_spectrum_log[3];

  /* FFT timer */
#ifdef DEBUG
  Timer_t *timer;
#endif

  double volume_scale;
  double volume;
  double maxpeak; /* highest peak on history buffer */
  double curpeak; /* highest peak on data2 */
  double average; /* average value on data2 */
  uint8_t on_beat; /* are we on frame where beat happens */
  double peakpower; /* power value (squared) of highest peak */
  double rms;     /* rms power of data2 */
} Input_t;


Input_t *Input_new(const uint32_t);

void Input_delete(Input_t *);
void Input_set(Input_t *, uint8_t);
/* void Input_reset_max_spectrum(Input_t *); */

/* MRNG stuff */
/* random float [-1.0 .. 1.0] */
float  Input_random_s_u_float(Input_t *);
/* random float [0.0 .. 1.0] */
float  Input_random_u_u_float(Input_t *);
/* random Pixel_t [0 .. 255] */
Pixel_t Input_random_color(Input_t *);
/* random float [min .. max] */
float  Input_random_float_range(Input_t *, const float, const float);
/* random short [min .. max] */
short  Input_random_short_range(Input_t *, const short, const short);

float  Input_get_volume(Input_t *);

uint8_t Input_toggle_mute(Input_t *);

/* volume scaling */
void   Input_volume_upscale(Input_t *);
void   Input_volume_downscale(Input_t *);
void   Input_set_volume_scale(Input_t *, const double);

double Input_clamp(const double);
void   Input_process(Input_t *);

/* signal processing */
double compute_avg_abs(double *buf, uint32_t a, uint32_t b);
uint16_t compute_avg_freq_id(Input_t *input, double spectrum_low_treshold_factor);

#endif /* INPUT_H */
