/*
 * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
 * Copyright (C) 2011 Pete Shorthose
 *
 * 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.
 * --------------------------------------------------------------------------
 *
 *
 *    This file is part of the Guitarix Audio Engine
 *
 *
 * --------------------------------------------------------------------------
 */

#pragma once

#ifndef SRC_HEADERS_TRANY_H_
#define SRC_HEADERS_TRANY_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 tranytab below will work.
 * Can't use inheritance because then C initializers will not
 * work and initialization will be more awkward or less efficient.
 */

namespace {

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

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

/*
 * data tables generated by tools/tube_transfer.py
 */
#include "KT88.cc"
#include "7199P.cc"
#include "SVEL34.cc"

enum {
    TRANY_TABLE_KT88_68k,
    TRANY_TABLE_KT88_250k,
    TRANY_TABLE_7199P_68k,
    TRANY_TABLE_7199P_250k,
    TRANY_TABLE_SVEL34_68k,
    TRANY_TABLE_SVEL34_250k,
    TRANY_TABLE_SIZE
};

table1d *tranytab[TRANY_TABLE_SIZE] = {
    &static_cast<table1d&>(tubetable_KT88[0]),
    &static_cast<table1d&>(tubetable_KT88[1]),
    &static_cast<table1d&>(tubetable_7199P[0]),
    &static_cast<table1d&>(tubetable_7199P[1]),
    &static_cast<table1d&>(tubetable_SVEL34[0]),
    &static_cast<table1d&>(tubetable_SVEL34[1]),
};

table1d *tranytab2[TRANY_TABLE_SIZE] = {
    &static_cast<table1d&>(tubetable2_7199P[0]),
    &static_cast<table1d&>(tubetable2_7199P[1]),
    &static_cast<table1d&>(tubetable2_SVEL34[0]),
    &static_cast<table1d&>(tubetable2_SVEL34[1]),
};

/*
 *  definitions for ffunction(float Ftrany(int,float), "trany.h", "");
 *  in gx_amp.dsp - gx_ampmodul.dsp
 */

static inline double Ftrany(int table, double Vgk) {
    const table1d& tab = *tranytab[table];
    double f = (Vgk - tab.low) * tab.istep;
    int i = static_cast<int>(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 Rtrany(int table, double Vgk) {
    const table1d& tab = *tranytab2[table];
    double f = (Vgk - tab.low) * tab.istep;
    int i = static_cast<int>(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  // SRC_HEADERS_TRANY_H_
