/*
 *  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/>.
 */

#include <sndfile.h>
#include "context.h"
#include "pthread_utils.h"


uint32_t options = BO_NONE;
uint32_t version = 0;

extern char *audio_file;
static SF_INFO     sfi;
static SNDFILE *sf = NULL;

/* compteur : nombre de frames restant a lire */
static sf_count_t frames;

/* taille du buffer Input */
static uint16_t bufsize;

/* loop on the file */
static uint8_t loop = 0;

extern uint8_t max_fps;


static int
open_file(void)
{
  /* ouvrir le fichier avec sndfile */
  sf = sf_open(audio_file, SFM_READ, &sfi);

  if (NULL == sf) {
    fprintf(stderr, "[!] sndfile: '%s': %s\n", audio_file, sf_strerror(sf));

    return -1;
  }

  /* initialiser le compteur de frames a lire */
  frames = sfi.frames;

  return 0;
}


int8_t
create(Context_t *ctx)
{
  if (NULL == audio_file) {
    audio_file = getenv("LEBINIOU_SNDFILE");
    if (NULL == audio_file) {
      fprintf(stderr, "[!] sndfile: no LEBINIOU_SNDFILE environment variable set and no command line option used !\n");

      return 0;
    }
  }
  VERBOSE(printf("[i] Reading file '%s'\n", audio_file));

  loop = (NULL != getenv("LEBINIOU_SNDFILE_LOOP"));
  if (open_file() == -1) {
    return 0;
  }

  /* creer une Input */
  bufsize = (uint16_t)((double)sfi.samplerate / max_fps);

  /* printf("[i] Input buffer size = %u\n", bufsize); */
  ctx->input = Input_new(bufsize);

  return 1;
}


void
destroy(Context_t *ctx)
{
  /* detruire l'input */
  Input_delete(ctx->input);

  /* fermer le fichier avec sndfile */
  sf_close(sf);
}


void
run(Context_t *ctx)
{
  /* la frame (sample[]) doit avoir, au moins, le meme nombre de canaux que le son a lire,
     meme si ce son a plus que 2 canaux, sinon sf_readf_double() crashe:
     depassement du buffer sample[] */
  double sample[sfi.channels];
  uint16_t idx;

  if (!xpthread_mutex_lock(&ctx->input->mutex)) {
    /* lire des datas du fichier et les coller dans l'Input */
    for (idx = 0; idx < bufsize; idx++) {
      /* lecture d'une frame du son en entree, au format double (comme pour l'Input) */
      if (frames > 0) {
        (void)sf_readf_double(sf, sample, 1);
        frames--;
      } else {
        /* plus de frames a lire, mettre les samples pour la fin du buffer a 0 */
        for (uint16_t ch = 0; ch < sfi.channels; ch++) {
          sample[ch] = 0;
        }
      }

      /* copier les samples de la frame lue dans le buffer input */
      if (sfi.channels < 2) {
        /* son mono : dupliquer le 1er sample dans les 2 canaux */
        ctx->input->data[A_LEFT][idx] = ctx->input->data[A_RIGHT][idx] = sample[0];
      } else {
        /* son stereo (ou plus) : ne prendre que les 2 premiers canaux */
        ctx->input->data[A_LEFT][idx] = sample[0];
        ctx->input->data[A_RIGHT][idx] = sample[1];
      }
    }
  }
  /* printf("[i] frames restant a lire = %llu\n", frames); */

  /* buffer pret, demander les FFT/u_data... */
  if (!ctx->input->mute) {
    Input_set(ctx->input, A_STEREO);
  }
  xpthread_mutex_unlock(&ctx->input->mutex);

  /* si lecture finie: on recommence ou on exit */
  if (frames < 1) {
    if (loop) {
      VERBOSE(printf("[i] sndfile: restarting stream '%s'\n", audio_file));

      /* rewind */
      if (-1 == sf_seek(sf, 0, SEEK_SET)) {
        xerror("sf_seek\n");
      }
      frames = sfi.frames;
    } else {
      ctx->running = 0;
      VERBOSE(printf("[i] sndfile: end of stream '%s'\n", audio_file));
    }
  }
}
