// Rar20Multimedia.cpp
// According to unRAR license,
// this code may not be used to develop a 
// RAR (WinRAR) compatible archiver

#include "StdAfx.h"

#include "Rar20Multimedia.h"

namespace NCompress {
namespace NRar20 {
namespace NMultimedia {

void CAudioVariables::Init()
{
  memset(this, 0, sizeof(CAudioVariables));
}

void CPredictor::Init()
{
  for(int i = 0; i < kNumChanelsMax; i++)
    m_AudioVariablesArray[i].Init();
  m_ChannelDelta = 0;
  CurrentChannel = 0;
}

Byte CPredictor::Predict()
{
  CAudioVariables *v = &m_AudioVariablesArray[CurrentChannel];
  v->ByteCount++;
  v->D4 = v->D3;
  v->D3 = v->D2;
  v->D2 = v->LastDelta-v->D1;
  v->D1 = v->LastDelta;
  int pCh = 8 * v->LastChar + 
            v->K1 * v->D1 + 
            v->K2 * v->D2 + 
            v->K3 * v->D3 + 
            v->K4 * v->D4 + 
            v->K5*m_ChannelDelta;
  pCh = (pCh >> 3) & 0xFF;
  return Byte(pCh);
}

void CPredictor::Update(Byte realValue, int predictedValue)
{
  struct CAudioVariables *v = &m_AudioVariablesArray[CurrentChannel];

  int delta = predictedValue - realValue;
  int i = ((signed char)delta) << 3;

  v->Dif[0] += abs(i);
  v->Dif[1] += abs(i - v->D1);
  v->Dif[2] += abs(i + v->D1);
  v->Dif[3] += abs(i - v->D2);
  v->Dif[4] += abs(i + v->D2);
  v->Dif[5] += abs(i - v->D3);
  v->Dif[6] += abs(i + v->D3);
  v->Dif[7] += abs(i - v->D4);
  v->Dif[8] += abs(i + v->D4);
  v->Dif[9] += abs(i - m_ChannelDelta);
  v->Dif[10] += abs(i + m_ChannelDelta);

  m_ChannelDelta = v->LastDelta = (signed char)(realValue - v->LastChar);
  v->LastChar = realValue;

  UInt32 numMinDif, minDif;
  if ((v->ByteCount & 0x1F)==0)
  {
    minDif = v->Dif[0];
    numMinDif = 0;
    v->Dif[0] = 0;
    for (i = 1; i < sizeof(v->Dif) / sizeof(v->Dif[0]); i++)
    {
      if (v->Dif[i] < minDif)
      {
        minDif = v->Dif[i];
        numMinDif = i;
      }
      v->Dif[i] = 0;
    }
    switch(numMinDif)
    {
      case 1:
        if (v->K1 >= -16)
          v->K1--;
        break;
      case 2:
        if (v->K1 < 16)
          v->K1++;
        break;
      case 3:
        if (v->K2 >= -16)
          v->K2--;
        break;
      case 4:
        if (v->K2 < 16)
          v->K2++;
        break;
      case 5:
        if (v->K3 >= -16)
          v->K3--;
        break;
      case 6:
        if (v->K3 < 16)
          v->K3++;
        break;
      case 7:
        if (v->K4 >= -16)
          v->K4--;
        break;
      case 8:
        if (v->K4 < 16)
          v->K4++;
        break;
      case 9:
        if (v->K5 >= -16)
          v->K5--;
        break;
      case 10:
        if (v->K5 < 16)
          v->K5++;
        break;
    }
  }
}

}}}
