// ----------------------------------------------------------------------------
//
//  Copyright (C) 2003-2022 Fons Adriaensen <fons@linuxaudio.org>
//    
//  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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <stdio.h>
#include <math.h>
#include "reverbs.h"


// -----------------------------------------------------------------------


const LADSPA_PortDescriptor Ladspa_zita_reverb::portdescr [NPORT] = 
{
    LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO,
    LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL
};


const char * const Ladspa_zita_reverb::portnames [NPORT] = 
{
  "In L",
  "In R",
  "Out L",
  "Out R",
  "Delay",
  "Xover",
  "RT-low",
  "RT-mid",
  "Damping",
  "F1-freq",
  "F1-gain",
  "F2-freq",
  "F2-gain",
  "Output mix"
};


const LADSPA_PortRangeHint Ladspa_zita_reverb::porthints [NPORT] = 
{
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE, 0.02f, 0.10f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_MIDDLE, 50.0f, 1e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW, 1.0f, 8.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW, 1.0f, 8.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_MIDDLE, 1.5e3f, 24e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_LOW, 40.0f, 10e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0, -20.0f, 20.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_HIGH, 40.0f, 10e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0, -20.0f, 20.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE, 0.0f, 1.0f }
};


LADSPA_Handle Ladspa_zita_reverb::create (const struct _LADSPA_Descriptor *desc, unsigned long rate)
{
    return new Ladspa_zita_reverb (rate);
}


void Ladspa_zita_reverb::setport (unsigned long port, LADSPA_Data *data)
{
    _port [port] = data;
}


void Ladspa_zita_reverb::active (bool act)
{
    _zreverb->reset ();
    _nprep = 0;
}


void Ladspa_zita_reverb::runproc (unsigned long frames, bool add)
{
    unsigned long k;
    float *inp [2] = { _port [A_INPL], _port [A_INPR] };
    float *out [2] = { _port [A_OUTL], _port [A_OUTR] };

    _zreverb->set_delay (_port [C_DELAY][0]);   
    _zreverb->set_xover (_port [C_XOVER][0]);   
    _zreverb->set_rtlow (_port [C_RTLOW][0]);   
    _zreverb->set_rtmid (_port [C_RTMID][0]);   
    _zreverb->set_fdamp (_port [C_FDAMP][0]);   
    _zreverb->set_eq1 (_port [C_FREQ1][0], _port [C_GAIN1][0]);
    _zreverb->set_eq2 (_port [C_FREQ2][0], _port [C_GAIN2][0]);
    _zreverb->set_opmix (_port [C_OPMIX][0]);
    while (frames)
    {
	if (!_nprep)
	{
	    _zreverb->prepare (FRAGM);
	    _nprep = FRAGM;
	}
	k = (_nprep < frames) ? _nprep : frames;
        _zreverb->process (k, inp, out);
        inp [0] += k;
        inp [1] += k;
        out [0] += k;
        out [1] += k;
	frames -= k;
	_nprep -= k;
    }
}


// -----------------------------------------------------------------------


const LADSPA_PortDescriptor Ladspa_zita_reverb_amb::portdescr [NPORT] = 
{
    LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO,
    LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL
};


const char * const Ladspa_zita_reverb_amb::portnames [NPORT] = 
{
  "In L",
  "In R",
  "Out W",
  "Out X",
  "Out Y",
  "Out Z",
  "Delay",
  "Xover",
  "RT-low",
  "RT-mid",
  "Damping",
  "F1-freq",
  "F1-gain",
  "F2-freq",
  "F2-gain",
  "XYZ gain"
};


const LADSPA_PortRangeHint Ladspa_zita_reverb_amb::porthints [NPORT] = 
{
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE, 0.02f, 0.10f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_MIDDLE, 50.0f, 1e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW, 1.0f, 8.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW, 1.0f, 8.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_MIDDLE, 1.5e3f, 24e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_LOW, 40.0f, 10e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0, -20.0f, 20.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_HIGH, 40.0f, 10e3f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0, -20.0f, 20.0f },
  { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0, -9.0f, 9.0f }
};


LADSPA_Handle Ladspa_zita_reverb_amb::create (const struct _LADSPA_Descriptor *desc, unsigned long rate)
{
    return new Ladspa_zita_reverb_amb (rate);
}


void Ladspa_zita_reverb_amb::setport (unsigned long port, LADSPA_Data *data)
{
    _port [port] = data;
}


void Ladspa_zita_reverb_amb::active (bool act)
{
    _zreverb->reset ();
    _nprep = 0;
}


void Ladspa_zita_reverb_amb::runproc (unsigned long frames, bool add)
{
    unsigned long k;
    float *inp [2] = { _port [A_INPL], _port [A_INPR] };
    float *out [4] = { _port [A_OUTW], _port [A_OUTX], _port [A_OUTY], _port [A_OUTZ] };

    _zreverb->set_delay (_port [C_DELAY][0]);   
    _zreverb->set_xover (_port [C_XOVER][0]);   
    _zreverb->set_rtlow (_port [C_RTLOW][0]);   
    _zreverb->set_rtmid (_port [C_RTMID][0]);   
    _zreverb->set_fdamp (_port [C_FDAMP][0]);   
    _zreverb->set_eq1 (_port [C_FREQ1][0], _port [C_GAIN1][0]);
    _zreverb->set_eq2 (_port [C_FREQ2][0], _port [C_GAIN2][0]);
    _zreverb->set_rgxyz (_port [C_RGXYZ][0]);
    while (frames)
    {
	if (!_nprep)
	{
	    _zreverb->prepare (FRAGM);
	    _nprep = FRAGM;
	}
	k = (_nprep < frames) ? _nprep : frames;
        _zreverb->process (k, inp, out);
        inp [0] += k;
        inp [1] += k;
        out [0] += k;
        out [1] += k;
        out [2] += k;
        out [3] += k;
	frames -= k;
	_nprep -= k;
    }
}
