//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2012 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.net                          *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  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.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
//function: crossfade (mixer) routines

#include "mpxplay.h"

extern unsigned int crossfadepart;

static int MIXER_var_pcmcrossfade;

static void clear_samples(char *pcm,unsigned int begin,unsigned int end,unsigned int bytespersample)
{
 if(pcm && (end>begin) && bytespersample)
  pds_memset(pcm+begin*bytespersample,0,(end-begin)*bytespersample);
}

static PCM_CV_TYPE_F *crossfade_config(struct mpxp_aumixer_passinfo_s *mpi,long *cf_v1,long *cf_v2)
{
 struct mainvars *mvp=mpi->mvp;
 struct crossfade_info *cfi=mvp->cfi;
 struct mpxpframe_s *frp0=mvp->frp0,*frp1=frp0+1;
 struct mpxp_aumixer_passinfo_s *mpi0=frp0->mpi;
 long v,v1,v2;
 PCM_CV_TYPE_F *cf_pcm2;

 if(crossfadepart==CROSS_FADE){
  struct mpxp_aumixer_passinfo_s *mpi1=frp1->mpi; // valid in crossfade only
  /*char sout[100];
  sprintf(sout,"s0:%4d s1:%4d f0:%d f1:%d fc:%d b0:%d %d b1:%d %d %8.8X %8.8X",
   mpi0->samplenum,mpi1->samplenum,
   mpi0->freq_song,mpi1->freq_song,mpi0->freq_card,
   mpi0->frp->pcmout_blocksize,frp0->pcmout_blocksize,
   mpi1->frp->pcmout_blocksize,frp1->pcmout_blocksize,
   (long)mpi0->frp,(long)mpi1->frp
   );
  pds_textdisplay_printf(sout);*/
  mpi->samplenum=(mpi0->samplenum)? mpi0->samplenum:mpi1->samplenum;
  // if the length of last block (of the 2 files) do not match (ogg,wav,ape files)
  clear_samples((char *)mpi0->pcm_sample,mpi0->samplenum,mpi->samplenum,mpi0->bytespersample_mixer); // (at end of file 1.)
  clear_samples((char *)mpi1->pcm_sample,mpi1->samplenum,mpi->samplenum,mpi1->bytespersample_mixer); // (at end of file 2.)(rare)
  cf_pcm2=(PCM_CV_TYPE_F *)mpi1->pcm_sample;
 }else{
  cf_pcm2=(PCM_CV_TYPE_F *)mpi0->pcm_sample;
 }

 if(crossfadepart&CFT_FADEOUT){
  struct mpxpframe_s *frp=(crossfadepart&CROSS_IN)? frp1:frp0;
  v=cfi->crossfadeend-frp->frameNum;
  if(v>0){
   if(cfi->crossfadetype&CFT_FADEOUT){
    v1=(v<<7)/cfi->crossfade_out_len;
    if(v1>128)
     v1=128;
   }else
    v1=128;
  }else{
   v1=0;
  }
 }else
  v1=0;
 if(crossfadepart&CFT_FADEIN){
  unsigned long index_pos=frp0->frameNum-frp0->index_start;
  v2=v1;
  v1=128;
  if(index_pos<cfi->crossfade_in_len){
   if(cfi->crossfadetype&CFT_FADEIN)
    v1=(index_pos<<7)/cfi->crossfade_in_len;
  }
 }else
  v2=0;

 *cf_v1=v1;
 *cf_v2=v2;

 return cf_pcm2;
}

//---------------------------------------------------------------------------
static void mixer_crossmix_process(struct mpxp_aumixer_passinfo_s *mpi)
{
 unsigned int i;
 PCM_CV_TYPE_F *pcm1,*pcm2;
 float fv1,fv2;
 long cf_v1,cf_v2;

 pcm2=(PCM_CV_TYPE_F *)crossfade_config(mpi,&cf_v1,&cf_v2);
 pcm1=(PCM_CV_TYPE_F *)mpi->pcm_sample;
 if(!pcm1 || !pcm2 || !mpi->samplenum)
  return;
 fv1=(float)cf_v1/128.0;
 fv2=(float)cf_v2/128.0;
 i=mpi->samplenum;
 do{
  pcm1[0]=pcm1[0]*fv1+pcm2[0]*fv2;
  pcm1++;pcm2++;
 }while(--i);
}

one_mixerfunc_info MIXER_FUNCINFO_crossfader={
 "MIX_CROSSFADER",
 NULL,
 &MIXER_var_pcmcrossfade,
 MIXER_INFOBIT_SWITCH,
 0,1,0,0,
 NULL,
 NULL,
 &mixer_crossmix_process,
 NULL,
 NULL
};
