Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

input.c

/*
 *  Copyright 1994-2011 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/>.
 */

#include "biniou.h"

/*
 * TODO cheesy display of the plan computed
 * TODO wisdom support (~/.lebiniou/biniou.wisdom)
 */

float phase = 1.0;

/* define to create the FFTW plan in a thread */
/* #define THREAD_PLAN */

static void
Input_rfftw_create_plan(Input_t *input)
{
  int c;

  for (c = 0; c < 3; ++c)
    input->plan_fft[c] = fftw_plan_r2r_1d(input->size,
                                input->data[c],
                                input->out[c],
                                (fftw_r2r_kind)FFTW_FORWARD,
                                FFTW_MEASURE
                                /* FFTW_REDFT00, */
                                /* FFTW_ESTIMATE */);
            
}


Input_t *
Input_new(const u_short size)
{
  int c;
#ifdef THREAD_PLAN
  pthread_t fftw_thread; 
#endif

  Input_t *input = xcalloc(1, sizeof(Input_t));

  pthread_mutex_init(&input->mutex, NULL);
      
  input->size = size;
  input->mute = 0;
  input->spectrum_size = input->size / 2 + 1;

  printf("[w] data size= %d, power spectrum size= %d\n",
       input->size, input->spectrum_size);

  for (c = 0; c < 3; c++) {
    /* FIXME breaks when compiling without libFFTW */
    input->data[c]   = (double *)fftw_malloc(sizeof(double) * input->size);
    input->data_u[c] = xcalloc(input->size, sizeof(double));
    input->out[c] = (double *)fftw_malloc(sizeof(double) * input->size);
    input->spectrum[c] = xcalloc(input->spectrum_size, sizeof(double));
    input->spectrum_norme[c] = xcalloc(input->spectrum_size, sizeof(double));
    input->spectrum_log[c] = xcalloc(input->spectrum_size, sizeof(double));
    input->spectrum_log_norme[c] = xcalloc(input->spectrum_size, sizeof(double));
  }

#ifdef THREAD_PLAN
  pthread_create(&fftw_thread, NULL, Input_rfftw_create_plan_threaded, input);
#else
  Input_rfftw_create_plan(input);
#endif
      
  return input;
}


void
Input_delete(Input_t *input)
{
  int c;

  for (c = 0; c < 3; c++) {
    fftw_free(input->data[c]);
    xfree(input->data_u[c]);
    fftw_free(input->out[c]);
    xfree(input->spectrum[c]);
    xfree(input->spectrum_norme[c]);
    xfree(input->spectrum_log[c]);
    xfree(input->spectrum_log_norme[c]);
    fftw_destroy_plan(input->plan_fft[c]);
  }

  xfree(input);
}


void *
Input_rfftw_create_plan_threaded(void *huhu)
{
  Input_t *input = (Input_t *)huhu;

  Input_rfftw_create_plan(input);
  printf("[i] FFTW plan created\n");

  pthread_exit(NULL);
}


static int
Input_seek_max_spectrum(Input_t *input, int c)
{
  int i;
  u_short new_max = 0;

  /* Input_reset_max_spectrum(input); */
  input->max_spectrum[c] = -1.0;
      
  /* start at 1 to avoid power spectrum value at index 0 */
  for (i = 1; i < input->spectrum_size; i++)
    if (input->spectrum[c][i] > input->max_spectrum[c]) {
      input->max_spectrum[c] = input->spectrum[c][i];
      new_max = i;
    }

  return new_max;
}


static void
Input_do_fft(Input_t *input)
{
  /* const int N = input->size; */
  /* const int even = (N % 2 == 0); */
  int c, k;

#ifdef THREAD_PLAN
  if (input->plan_fft != NULL)
#endif
    /* could be optimized, ie only do FFTs on LEFT and RIGHT and compute MONO spectrums.
       well, i'm too lazy :) --oliv3 */
    for (c = 0; c < 3; c++)
      fftw_execute(input->plan_fft[c]);

  for (c = 0; c < 3; c++) {
    for (k = 0; k < input->size; k++) {
      input->out[c][k] /= (float)input->size;
      /*  printf("(%d %d %f) ", c, k, input->out[c][k]); */
    }
#if 0

    input->spectrum[c][0] = input->out[c][0] * input->out[c][0];  /* DC component */

    for (k = 1; k < input->spectrum_size; ++k)  /* (k < N/2 rounded up) */
      input->spectrum[c][k] = input->out[c][k] * input->out[c][k] + input->out[c][N-k] * input->out[c][N-k];
    
    if (even) /* N is even */
      input->spectrum[c][input->spectrum_size-1] = input->out[c][input->spectrum_size-1] * input->out[c][input->spectrum_size-1];  /* Nyquist freq. */
#else
    for (k = 0; k < input->spectrum_size; k++)
      input->spectrum[c][k] = input->out[c][k];
#endif
  }

  for (c = 0; c < 3; c++) {
    int new_max = Input_seek_max_spectrum(input, c);

    for (k = 0; k < input->spectrum_size; ++k) {
      input->spectrum_norme[c][k]     = sqrtf(input->spectrum[c][k]);
      /* Log toussa */
      /* log1p(x)=logf(x+1) */
      input->spectrum_log  [c][k]     = log1p(input->spectrum[c][k]) / (M_LN2 / M_LN10);
      input->spectrum_log_norme[c][k] = log1p(input->spectrum_norme[c][k]) / (M_LN2 / M_LN10);
    }

    input->max_spectrum_norme[c] = input->spectrum_norme[c][new_max];
    input->max_spectrum_log[c] = input->spectrum_log[c][new_max];
    input->max_spectrum_log_norme[c] = input->spectrum_log_norme[c][new_max];

#if 0 /* def DEBUG */
    printf("[s] Spectrum: max on channel %d\n"
         "[s]   spectrum: %f\n"
         "[s]   spectrum_norme: %f\n"
         "[s]   spectrum_log: %f\n"
         "[s]   spectrum_log_norme: %f\n\n",
         c,
         input->max_spectrum[c],
         input->max_spectrum_norme[c],
         input->max_spectrum_log[c],
         input->max_spectrum_log_norme[c]);
#endif
  }
}


inline double
Input_clamp(const double val)
{
  if (val < -1.0) return -1.0;
  else if (val > 1.0) return 1.0;
  else return val;
}


void
Input_set(Input_t *input, u_char mode)
{
  /* mode:
   * A_MONO   => copy A_MONO to A_LEFT and A_RIGHT
   * A_STEREO => compute A_MONO as the average of A_LEFT and A_RIGHT
   */
  int i, j;

  pthread_mutex_lock(&input->mutex);

  if (mode == A_MONO)
    for (i = 0, j = 0; i < input->size; i++, j++) {
      /* clamp values */
      input->data[A_MONO][i] = Input_clamp(input->data[A_MONO][i]);

      /* set input from A_MONO source */
      input->data_u[A_MONO][j] = (input->data[A_MONO][i] + 1.0) / 2;

      /* copy to A_LEFT and A_RIGHT */
      input->data[A_LEFT][j] = input->data[A_RIGHT][j] = input->data[A_MONO][i];
      input->data_u[A_LEFT][j] = input->data_u[A_RIGHT][j] = input->data_u[A_MONO][i];
    }
  else {
    assert(mode == A_STEREO);
    for (i = 0, j = 0; i < input->size; i ++, j++) {
      /* clamp values */
      input->data[A_LEFT][i] = Input_clamp(input->data[A_LEFT][i]);
      input->data[A_RIGHT][i] = Input_clamp(input->data[A_RIGHT][i]);

      /* set input from A_LEFT and A_RIGHT */
      input->data_u[A_LEFT][j] = (input->data[A_LEFT][i] + 1.0) / 2;
      input->data_u[A_RIGHT][j] = (input->data[A_RIGHT][i] + 1.0) / 2;

      /* compute A_MONO from A_LEFT and A_RIGHT */
      input->data[A_MONO][j] = Input_clamp((input->data[A_LEFT][i] + phase * input->data[A_RIGHT][i]) / 2);
      input->data_u[A_MONO][j] = (input->data[A_MONO][j] + 1.0) / 2;
    }
  }

  Input_do_fft(input);

  pthread_mutex_unlock(&input->mutex);
}


static inline void
do_roulette(Input_t *input)
{
  INC(input->roulette, input->size);
}


inline float
Input_random_s_u_float(Input_t *input)
{
  /* random float [-1..+1] */
  float f = input->data[A_MONO][input->roulette];
  do_roulette(input);
  return f;
}


inline float
Input_random_u_u_float(Input_t *input)
{
  /* random float [0..1] */
  float f = input->data_u[A_MONO][input->roulette];
  do_roulette(input);
  return f;
}


inline float
Input_random_float_range(Input_t *input, const float min, const float max)
{
  /* random short */
  float f;
  float rnd = input->data_u[A_MONO][input->roulette];
#ifdef DEBUG
  if (max <= min)
    xerror ("Input_random_short_range: max %f <= min %f\n", max, min);
#endif
  f = min + rnd * (max - min);
  do_roulette(input);
  return f;
}


inline short
Input_random_short_range(Input_t *input, const short min, const short max)
{
  /* random short */
  short s;
  float rnd = input->data_u[A_MONO][input->roulette];
#ifdef DEBUG
  if (max <= min)
    xerror ("Input_random_short_range: max %d <= min %d\n", max, min);
#endif
  s = min + rnd * (max - min);
  do_roulette(input);
  return s;
}


inline u_char
Input_random_u_char(Input_t *input)
{
  u_char uc = (input->data_u[A_MONO][input->roulette] * 255);

  do_roulette(input);
  return uc;
}


inline float
Input_get_volume(Input_t *input)
{
  u_short i;
  float volume = 0;

  pthread_mutex_lock(&input->mutex);

  for (i = 0; i < input->size; i++)
    volume += fabs(input->data[A_MONO][i]);

  volume /= input->size;

  pthread_mutex_unlock(&input->mutex);

  return volume;
}

Generated by  Doxygen 1.6.0   Back to index