/*
 * Copyright (C) 2012 Hermann Meyer, Andreas Degert, Pete Shorthose, Steve Poskitt
 *
 * 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 of the License, 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * --------------------------------------------------------------------------
 */


#pragma once

#ifndef SRC_HEADERS_VALVE_H_
#define SRC_HEADERS_VALVE_H_

/****************************************************************
 * 1-dimensional function tables for linear interpolation
 *
 * table1d and table1d_imp<size> must only differ in the last
 * element, so that the typecast for tubetab below will work.
 * Can't use inheritance because then C initializers will not
 * work and initialization will be more awkward or less efficient.
 */

struct table1d   // 1-dimensional function table
{
  float low;
  float high;
  float istep;
  int32_t size;
  float data[];
};

template <int32_t tab_size>
struct table1d_imp
{
  float low;
  float high;
  float istep;
  int32_t size;
  float data[tab_size];
  operator table1d&() const
  {
    return *(table1d*)this;
  }
};

/*
 * data tables generated by tools/tube_transfer.py
 */
#include "12ax7.cc"
#include "12AU7.cc"
#include "12AT7.cc"
#include "6V6.cc"
#include "6DJ8.cc"
#include "6C16.cc"
#include "6L6CG.cc"
#include "EL34.cc"
#include "12AY7.cc"
#include "JJECC83S.cc"
#include "JJECC99.cc"
#include "EL84.cc"
#include "EF86.cc"
#include "SVEL34.cc"

enum {
    TUBE_TABLE_12AX7_68k,
    TUBE_TABLE_12AX7_250k,
    TUBE_TABLE_6V6_68k,
    TUBE_TABLE_6V6_250k,
    TUBE_TABLE_12AU7_68k,
    TUBE_TABLE_12AU7_250k,
    TUBE_TABLE_6DJ8_68k,
    TUBE_TABLE_6DJ8_250k,
    TUBE_TABLE_12AT7_68k,
    TUBE_TABLE_12AT7_250k,
    TUBE_TABLE_6C16_68k,
    TUBE_TABLE_6C16_250k,
    TUBE_TABLE_6L6CG_68k,
    TUBE_TABLE_6L6CG_250k,
    TUBE_TABLE_EL34_68k,
    TUBE_TABLE_EL34_250k,
    TUBE_TABLE_12AY7_68k,
    TUBE_TABLE_12AY7_250k,
    TUBE_TABLE_JJECC83S_68k,
    TUBE_TABLE_JJECC83S_250k,
    TUBE_TABLE_JJECC99_68k,
    TUBE_TABLE_JJECC99_250k,
    TUBE_TABLE_EL84_68k,
    TUBE_TABLE_EL84_250k,
    TUBE_TABLE_EF86_68k,
    TUBE_TABLE_EF86_250k,
    TUBE_TABLE_SVEL34_68k,
    TUBE_TABLE_SVEL34_250k,
    TUBE_TABLE_SIZE
};

table1d *tubetab[TUBE_TABLE_SIZE] = {
    &static_cast<table1d&>(tubetable_12AX7[0]),
    &static_cast<table1d&>(tubetable_12AX7[1]),
    &static_cast<table1d&>(tubetable_6V6[0]),
    &static_cast<table1d&>(tubetable_6V6[1]),
    &static_cast<table1d&>(tubetable_12AU7[0]),
    &static_cast<table1d&>(tubetable_12AU7[1]),
    &static_cast<table1d&>(tubetable_6DJ8[0]),
    &static_cast<table1d&>(tubetable_6DJ8[1]),
    &static_cast<table1d&>(tubetable_12AT7[0]),
    &static_cast<table1d&>(tubetable_12AT7[1]),
    &static_cast<table1d&>(tubetable_6C16[0]),
    &static_cast<table1d&>(tubetable_6C16[1]),
    &static_cast<table1d&>(tubetable_6L6CG[0]),
    &static_cast<table1d&>(tubetable_6L6CG[1]),
    &static_cast<table1d&>(tubetable_EL34[0]),
    &static_cast<table1d&>(tubetable_EL34[1]),
    &static_cast<table1d&>(tubetable_12AY7[0]),
    &static_cast<table1d&>(tubetable_12AY7[1]),
    &static_cast<table1d&>(tubetable_JJECC83S[0]),
    &static_cast<table1d&>(tubetable_JJECC83S[1]),
    &static_cast<table1d&>(tubetable_JJECC99[0]),
    &static_cast<table1d&>(tubetable_JJECC99[1]),
    &static_cast<table1d&>(tubetable_EL84[0]),
    &static_cast<table1d&>(tubetable_EL84[1]),
    &static_cast<table1d&>(tubetable_EF86[0]),
    &static_cast<table1d&>(tubetable_EF86[1]),
    &static_cast<table1d&>(tubetable_SVEL34[0]),
    &static_cast<table1d&>(tubetable_SVEL34[1]),
};

table1d *tubetab2[TUBE_TABLE_SIZE] = {
    &static_cast<table1d&>(tubetable2_12AX7[0]),
    &static_cast<table1d&>(tubetable2_12AX7[1]),
    &static_cast<table1d&>(tubetable2_6V6[0]),
    &static_cast<table1d&>(tubetable2_6V6[1]),
    &static_cast<table1d&>(tubetable2_12AU7[0]),
    &static_cast<table1d&>(tubetable2_12AU7[1]),
    &static_cast<table1d&>(tubetable2_6DJ8[0]),
    &static_cast<table1d&>(tubetable2_6DJ8[1]),
    &static_cast<table1d&>(tubetable2_12AT7[0]),
    &static_cast<table1d&>(tubetable2_12AT7[1]),
    &static_cast<table1d&>(tubetable2_6C16[0]),
    &static_cast<table1d&>(tubetable2_6C16[1]),
    // using old tube table in gxmetal_head!!
    //&static_cast<table1d&>(tubetable2_6L6CG[0]),
    //&static_cast<table1d&>(tubetable2_6L6CG[1]),
    &static_cast<table1d&>(tubetable2_EL34[0]),
    &static_cast<table1d&>(tubetable2_EL34[1]),
    &static_cast<table1d&>(tubetable2_12AY7[0]),
    &static_cast<table1d&>(tubetable2_12AY7[1]),
    &static_cast<table1d&>(tubetable2_JJECC83S[0]),
    &static_cast<table1d&>(tubetable2_JJECC83S[1]),
    &static_cast<table1d&>(tubetable2_JJECC99[0]),
    &static_cast<table1d&>(tubetable2_JJECC99[1]),
    &static_cast<table1d&>(tubetable2_EL84[0]),
    &static_cast<table1d&>(tubetable2_EL84[1]),
    &static_cast<table1d&>(tubetable2_EF86[0]),
    &static_cast<table1d&>(tubetable2_EF86[1]),
    &static_cast<table1d&>(tubetable2_SVEL34[0]),
    &static_cast<table1d&>(tubetable2_SVEL34[1]),
};
/*
 *  definitions for ffunction(float Ftube(int32_t,float), "valve.h", "");
 *  in gx_amp.dsp - gx_ampmodul.dsp
 */

static inline double Ftube(int32_t table, double Vgk)
{
  const table1d& tab = *tubetab[table];
  double f = (Vgk - tab.low) * tab.istep;
  int32_t i = static_cast<int32_t>(f);
  if (i < 0)
    return tab.data[0];
  if (i >= tab.size-1)
    return tab.data[tab.size-1];
  f -= i;
  return tab.data[i]*(1-f) + tab.data[i+1]*f;
}

static inline double Ranode(int32_t table, double Vgk)
{
  const table1d& tab = *tubetab2[table];
  double f = (Vgk - tab.low) * tab.istep;
  int32_t i = static_cast<int32_t>(f);
  if (i < 0)
    return tab.data[0];
  if (i >= tab.size-1)
    return tab.data[tab.size-1];
  f -= i;
  return tab.data[i]*(1-f) + tab.data[i+1]*f;
}

#endif
