///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// File:           CC121EqMap.cpp                                            //
//                                                                           //
// Functionality:  EQ parameter map class implementation.                    //
//                                                                           //
// Author:         Rolf Meyerhoff (rm@matrix44.de)                           //
//                                                                           //
// Copyright:      (C) 2009 by Rolf Meyerhoff. All rights reserved.          //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// License:                                                                  //
//                                                                           //
// This library is free software;  you can redistribute it  and/or modify it //
// under the terms of the GNU Lesser  General Public License as published by //
// the Free Software Foundation;  either version 2.1 of the License,  or (at //
// your option) any later version.                                           //
//                                                                           //
// This  library 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 Lesser //
// General Public License for more details.                                  //
//                                                                           //
// You should have received a copy of  the GNU Lesser General Public License //
// along with this library;  if not,  write to the Free Software Foundation, //
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.              //
///////////////////////////////////////////////////////////////////////////////
#include "reaper_cc121.h"

///////////////////////////////////////////////////////////////////////////////
// CC121EqMap::CC121EqMap()
///////////////////////////////////////////////////////////////////////////////
// Description:  Default constructor of this class.
// Parameters:   None.
// Return value: No return value.
// Remarks:      Just initializes the members of this class.
///////////////////////////////////////////////////////////////////////////////
CC121EqMap::CC121EqMap() :
  qScaling(4000.0),
  fScaling(6000.0),
  gScaling(4000.0),
  tScaling(1.0)
{
  // Init empty:
  for (int entry = 0; entry < (sizeof(eq_map) / sizeof(eq_map[0])); entry++)
    eq_map[entry] = -1;
}
  
///////////////////////////////////////////////////////////////////////////////
// CC121EqMap::CC121EqMap()
///////////////////////////////////////////////////////////////////////////////
// Description:  Copy constructor of this class.
// Parameters:   [in] other: The source class to copy.
// Return value: No return value.
// Remarks:      Just copies the members of the source class.
///////////////////////////////////////////////////////////////////////////////
CC121EqMap::CC121EqMap(const CC121EqMap& other) :
  mapName(other.mapName),
  qScaling(other.qScaling),
  fScaling(other.fScaling),
  gScaling(other.gScaling),
  tScaling(other.tScaling)
{
  // Copy map:
  memcpy(eq_map, other.eq_map, sizeof(eq_map));
}

///////////////////////////////////////////////////////////////////////////////
// CC121EqMap::~CC121EqMap()
///////////////////////////////////////////////////////////////////////////////
// Description:  Destructor of this class.
// Parameters:   None.
// Return value: No return value.
// Remarks:      Clears up all allocated resources.
///////////////////////////////////////////////////////////////////////////////
CC121EqMap::~CC121EqMap()
{
  // Nothing to do here.
}

///////////////////////////////////////////////////////////////////////////////
// CC121EqMap::()
///////////////////////////////////////////////////////////////////////////////
// Description:  .
// Parameters:   None.
// Return value: No return value.
// Remarks:      .
///////////////////////////////////////////////////////////////////////////////
const std::string& CC121EqMap::getMapName() const
{
  // Return current name:
  return mapName;
}

///////////////////////////////////////////////////////////////////////////////
// CC121EqMap::MapParameter()
///////////////////////////////////////////////////////////////////////////////
// Description:  Map EQ control to EQ parameter number.
// Parameters:   [in]  param:   Parameter type, see enum above.
//               [in]  channel: Channel / column of the parameter (1 - 4).
//               [out] scale:   Scaling of the parameter, may be NULL.
// Return value: Returns the ID of the parameter or -1 if unassigned.
// Remarks:      The channel is ignored for the Bypass/Mix parameters.
///////////////////////////////////////////////////////////////////////////////
int CC121EqMap::MapParameter(const EqParam param, const int channel, double* scale) const
{
  // Last parameters are overall bypass and mix:
  if (param == EqBypass)
    return eq_map[20];
  else if (param == EqMix)
    return eq_map[21];

  // Set scaling:
  if (scale != 0)
  {
    switch (param)
    {
    case Q:
      *scale = qScaling;
      break;
    case Frequency:
      *scale = fScaling;
      break;
    case Gain:
      *scale = gScaling;
      break;
    case Type:
      *scale = tScaling;
      break;
    }
  }

  // Map parameter:
  return eq_map[param * 4 + channel];
}

/////////////////////////////////////////////////////////////////////////////////
// CC121EqMap::LoadMap()
/////////////////////////////////////////////////////////////////////////////////
// Description:  Load a single EQ map from file.
// Parameters:   [in] fileName: Name of the file to load.
// Return value: Returns true on success or false otherwise.
// Remarks:      EQ maps have a *.eqmap extension.
/////////////////////////////////////////////////////////////////////////////////
bool CC121EqMap::LoadMap(const char* fileName)
{
  // Parameter check:
  if (!fileName)
    return false;

  // Open the file:
  FILE* f = fopen(fileName, "rb");
  if (!f)
    return false;

  // Get file size:
  fseek(f, 0, SEEK_END);
  long fsize = ftell(f);
  fseek(f, 0, SEEK_SET);

  // Allocate text buffer:
  char* buff = new char[fsize + 1];
  memset(buff, 0, fsize);

  // Read the file:
  if (fread(buff, 1, fsize, f) != fsize)
  {
    // Error return:
    delete [] buff;
    fclose(f);
    return false;
  }

  // Close the file:
  fclose(f);

  // Init empty:
  for (int entry = 0; entry < (sizeof(eq_map) / sizeof(eq_map[0])); entry++)
    eq_map[entry] = -1;

  // Chop buffer:
  char* ptr = strtok(buff, "\n");
  while (ptr)
  {
    // Remove initial white spaces:
    while (*ptr == ' ')
      ptr++;

    // Extract ID:
    // TODO: Check for endian problems on other platforms:
    short id = (ptr[0] << 8) | ptr[1];

    // Seek to value:
    while (*ptr && *ptr != '=')
      ptr++;
    while (*ptr == ' ' || *ptr == '=')
      ptr++;

    // Extract values:
    if (id == 'ID')
    {
      // Remove non printable chars:
      char* tptr = ptr;
      while (*tptr)
      {
        if (!isprint(*tptr))
        {
          *tptr = 0;
          break;
        }
        tptr++;
      }

      // Set name:
      mapName = std::string(ptr);
    }
    else
    {
      // Get numeric value:
      int val = atoi(ptr);
      if (val == 0 && errno == ERANGE)
        continue;

      // Assign to map entry:
      switch (id)
      {
      case 'Q1': eq_map[ 0] = val; break;
      case 'Q2': eq_map[ 1] = val; break;
      case 'Q3': eq_map[ 2] = val; break;
      case 'Q4': eq_map[ 3] = val; break;
      case 'F1': eq_map[ 4] = val; break;
      case 'F2': eq_map[ 5] = val; break;
      case 'F3': eq_map[ 6] = val; break;
      case 'F4': eq_map[ 7] = val; break;
      case 'G1': eq_map[ 8] = val; break;
      case 'G2': eq_map[ 9] = val; break;
      case 'G3': eq_map[10] = val; break;
      case 'G4': eq_map[11] = val; break;
      case 'T1': eq_map[12] = val; break;
      case 'T2': eq_map[13] = val; break;
      case 'T3': eq_map[14] = val; break;
      case 'T4': eq_map[15] = val; break;
      case 'B1': eq_map[16] = val; break;
      case 'B2': eq_map[17] = val; break;
      case 'B3': eq_map[18] = val; break;
      case 'B4': eq_map[19] = val; break;
      case 'BP': eq_map[20] = val; break;
      case 'MX': eq_map[21] = val; break;
      case 'QS': qScaling = val; break;
      case 'FS': fScaling = val; break;
      case 'GS': gScaling = val; break;
      case 'TS': tScaling = val; break;
      }
    }

    // Next line:
    ptr = strtok(NULL, "\n");
  }

  // Cleanup:
  delete [] buff;

  // Return success:
  return true;
}

///////////////////////////////// End of File /////////////////////////////////
