/**************************************************************************
 * Copyright (C) 2008 Cocha                                               *
 * http://sourceforge.jp/projects/ecodecotool/                            *
 *                                                                        *
 *  This Program 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, 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 General Public License for more details.                          *
 *                                                                        *
 *  You should have received a copy of the GNU General Public License     *
 *  along with GNU Make; see the file COPYING.  If not, write to          *
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *
 *                                                                        *
 **************************************************************************/

#include "ConvertWav.h"


HRESULT CConvertChannels::SetFormat(WAVEFORMATEX *pInFormat, WAVEFORMATEX *pOutFormat)
{
   
   ::CopyMemory(&m_inFormat, pInFormat, sizeof(m_inFormat));
   ::CopyMemory(&m_outFormat, pOutFormat, sizeof(m_outFormat));

   return S_OK;
}

HRESULT CConvertChannels::Convert(BYTE *pInData, int nInLength, BYTE *pOutData, int *pnOutLength)
{  

   int i, j;

   if(m_inFormat.nChannels == 1 && m_outFormat.nChannels == 2)
   {  

      int nInBytesPerSample = m_inFormat.wBitsPerSample / 8;
      int nOutBytesPerSample = 2 * m_outFormat.wBitsPerSample / 8;

      for(i=0,j=0; i<nInLength; i+=nInBytesPerSample,j+=nOutBytesPerSample)
      {
         ::CopyMemory(&pOutData[j], &pInData[i], nInBytesPerSample);
         ::CopyMemory(&pOutData[j+nInBytesPerSample], &pInData[i], nInBytesPerSample);
      }

      *pnOutLength = j;
      return S_OK;
   }

   if(m_inFormat.nChannels == 2 && m_outFormat.nChannels == 1)
   {  

      if(m_inFormat.wFormatTag == WAVE_FORMAT_PCM)
      {
         if(m_inFormat.wBitsPerSample == 8)
         {  

            int nLeft;

            for(i=0,j=0; i<nInLength; i+=2,j++)
            {
               nLeft = (int)pInData[i] + (int)pInData[i+1];
               if(nLeft > 255)
                  nLeft = 255;

               pOutData[j] = (BYTE)nLeft;
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 16)
         {  

            int nLeft;
            short sData[2];

            for(i=0,j=0; i<nInLength; i+=4,j+=2)
            {
               ::CopyMemory(sData, &pInData[i], 4);

               nLeft = (int)sData[0] + (int)sData[1];
               if(nLeft > 32767)
                  nLeft = 32767;

               if(nLeft < -32768)
                  nLeft = -32768;

               sData[0] = (short)nLeft;
               ::CopyMemory(&pOutData[j], &sData[0], 2);
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 24)
         {  

            int nData[2];

            for(i=0,j=0; i<nInLength; i+=6,j+=3)
            {

               nData[0] = (pInData[i+2] << 16) | (pInData[i+1] << 8) | pInData[i];
               if(pInData[i+2] & 0x80)
                  nData[0] |= 0xff000000;

               nData[1] = (pInData[i+5] << 16) | (pInData[i+4] << 8) | pInData[i+3];
               if(pInData[i+5] & 0x80)
                  nData[1] |= 0xff000000;

               nData[0] = nData[0] + nData[1];

               if(nData[0] > 8388607)
                  nData[0] = 8388607;

               if(nData[0] < -8388608)
                  nData[0] = -8388608;

               pOutData[j] = (nData[0] & 0x000000ff);
               pOutData[j+1] = (nData[0] & 0x0000ff00) >> 8;
               pOutData[j+2] = (nData[0] & 0x00ff0000) >> 16;
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 32)
         {  

            int nData[2];
            double dLeft;

            for(i=0,j=0; i<nInLength; i+=8,j+=4)
            {
               ::CopyMemory(&nData[0], &pInData[i], 8);

               dLeft = (double)nData[0] + (double)nData[1];

               if(dLeft > 2147483647.0)
                  dLeft = 2147483647.0;

               if(dLeft < -2147483648.0)
                  dLeft = -2147483648.0;

               nData[0] = (int)dLeft;

               ::CopyMemory(&pOutData[j], &nData[0], 4);
            }

            *pnOutLength = j;
            return S_OK;
         }
      }
      else if(m_inFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
      {
         if(m_inFormat.wBitsPerSample == 32)
         {  
            float fData[2];

            for(i=0,j=0; i<nInLength; i+=8,j+=4)
            {
               ::CopyMemory(&fData[0], &pInData[i], 8);
               fData[0] = fData[0] + fData[1];

               if(fData[0] > 1.0f)
                  fData[0] = 1.0f;

               if(fData[0] < -1.0f)
                  fData[0] = -1.0f;

               ::CopyMemory(&pOutData[j], &fData[0], 4);
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 64)
         {  
            double dData[2];

            for(i=0,j=0; i<nInLength; i+=16,j+=8)
            {
               ::CopyMemory(&dData[0], &pInData[i], 16);
               dData[0] = dData[0] + dData[1];

               if(dData[0] > 1.0)
                  dData[0] = 1.0;

               if(dData[0] < -1.0)
                  dData[0] = -1.0;

               ::CopyMemory(&pOutData[j], &dData[0], 8);
            }

            *pnOutLength = j;
            return S_OK;
         }
      }
   }

   return E_FAIL;
}

HRESULT CConvertChannels::Convert(BYTE *pInData, int nInLength, int *pnOutLength)
{  

   

   
   

   int i, j;

   if(m_inFormat.nChannels == 1 && m_outFormat.nChannels == 2)
   {  

      int nInBytesPerSample = m_outFormat.wBitsPerSample / 8;
      int nOutBytesPerSample = 2 * nInBytesPerSample;

      for(i=(nInLength-nInBytesPerSample),j=(nInLength*2-nOutBytesPerSample); i>=0; i-=nInBytesPerSample,j-=nOutBytesPerSample)
      {  

         ::MoveMemory(&pInData[j], &pInData[i], nInBytesPerSample);
         ::MoveMemory(&pInData[j+nInBytesPerSample], &pInData[i], nInBytesPerSample);
      }

      *pnOutLength = nInLength * 2;
      return S_OK;
   }
   else if(m_inFormat.nChannels == 2 && m_outFormat.nChannels == 1)
   {  

      if(m_inFormat.wFormatTag == WAVE_FORMAT_PCM)
      {
         if(m_inFormat.wBitsPerSample == 8)
         {  
            int nLeft;

            for(i=0,j=0; i<nInLength; i+=2,j++)
            {  

               nLeft = (int)pInData[i] + (int)pInData[i+1];
               if(nLeft > 255)
                  nLeft = 255;

               pInData[j] = (BYTE)nLeft;
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 16)
         {  
            int nLeft;
            short sData[2];

            for(i=0,j=0; i<nInLength; i+=4,j+=2)
            {  
               ::CopyMemory(&sData[0], &pInData[i], 4);

               nLeft = (int)sData[0] + (int)sData[1];
               if(nLeft > 32767)
                  nLeft = 32767;

               if(nLeft < -32768)
                  nLeft = -32768;

               sData[0] = (short)nLeft;
               ::CopyMemory(&pInData[j], &sData[0], 2);
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 24)
         {  
            int nData[2];

            for(i=0,j=0; i<nInLength; i+=6,j+=3)
            {  

               nData[0] = (pInData[i+2] << 16) | (pInData[i+1] << 8) | pInData[i];
               if(pInData[i+2] & 0x80)
                  nData[0] |= 0xff000000;

               nData[1] = (pInData[i+5] << 16) | (pInData[i+4] << 8) | pInData[i+3];
               if(pInData[i+5] & 0x80)
                  nData[1] |= 0xff000000;

               nData[0] = nData[0] + nData[1];

               if(nData[0] > 8388607)
                  nData[0] = 8388607;

               if(nData[0] < -8388608)
                  nData[0] = -8388608;

               pInData[j] = (nData[0] & 0x000000ff);
               pInData[j+1] = (nData[0] & 0x0000ff00) >> 8;
               pInData[j+2] = (nData[0] & 0x00ff0000) >> 16;
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 32)
         {  

            int nData[2];
            double dLeft;

            for(i=0,j=0; i<nInLength; i+=8,j+=4)
            {  
               ::CopyMemory(&nData[0], &pInData[i], 8);

               dLeft = (double)nData[0] + (double)nData[1];

               if(dLeft > 2147483647.0)
                  dLeft = 2147483647.0;

               if(dLeft < -2147483648.0)
                  dLeft = -2147483648.0;

               nData[0] = (int)dLeft;
               ::CopyMemory(&pInData[j], &nData[0], 4);
            }

            *pnOutLength = j;
            return S_OK;
         }
      }
      else if(m_inFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
      {
         if(m_inFormat.wBitsPerSample == 32)
         {  
            float fData[2];

            for(i=0,j=0; i<nInLength; i+=8,j+=4)
            {  
               ::CopyMemory(&fData[0], &pInData[i], 8);

               fData[0] = fData[0] + fData[1];

               if(fData[0] > 1.0f)
                  fData[0] = 1.0f;

               if(fData[0] < -1.0f)
                  fData[0] = -1.0f;

               ::CopyMemory(&pInData[j], &fData[0], 4);
            }

            *pnOutLength = j;
            return S_OK;
         }
         else if(m_inFormat.wBitsPerSample == 64)
         {  
            double dData[2];

            for(i=0,j=0; i<nInLength; i+=16,j+=8)
            {  
               ::CopyMemory(&dData[0], &pInData[i], 16);

               dData[0] = dData[0] + dData[1];

               if(dData[0] > 1.0)
                  dData[0] = 1.0;

               if(dData[0] < -1.0)
                  dData[0] = -1.0;

               ::CopyMemory(&pInData[j], &dData[0], 8);
            }

            *pnOutLength = j;
            return S_OK;
         }
      }
   }

   return E_FAIL;
}

