// ----------------------------------------------------------------------------
//
//  Copyright (C) 2003-2013 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "sgenwin.h"
#include "styles.h"



Sgenwin::Sgenwin (X_window *parw, X_resman *resman, X_callback *callb) :
    X_window (parw, XPOS, YPOS, XDEF, YDEF, XftColors.main_bg->pixel),
    _callb (callb),
    _rate (0)
{
    X_hints H;
    char    s [1024];

    _xatom = XInternAtom (dpy (), "WM_DELETE_WINDOW", True);
    XSetWMProtocols (dpy (), win (), &_xatom, 1);
    _xatom = XInternAtom (dpy (), "WM_PROTOCOLS", True);

    H.size (XDEF, YDEF);
    H.minsize (XDEF, YDEF);
    H.maxsize (XDEF, YDEF);
    H.position (XPOS, YPOS);
    H.rname (resman->rname ());
    H.rclas (resman->rclas ());
    x_apply (&H); 

    sprintf (s, "%s-%s  [%s]   Sweep", PROGNAME, VERSION, resman->rname ());
    x_set_title (s);
    x_add_events (ExposureMask);

    _ready = new X_textip (this, 0, &Tst0, 330, 10, 50, 17, 7);
    _ready->set_text ("Ready");
    _tname = new X_textip (this, this, &Tst1, 100,  10, 220, 17, 256);
    _tname->x_map ();
    _trate = new X_textip (this, this, &Tst1, 100,  34,  80, 17, 256, _tname);
    _trate->x_map ();
    _ttim1 = new X_textip (this, this, &Tst1, 100,  58,  80, 17, 256, _trate);
    _ttim1->set_text ("0.1");
    _ttim1->x_map ();
    _tfmin = new X_textip (this, this, &Tst1, 100,  82,  80, 17, 256, _ttim1);
    _tfmin->set_text ("20");
    _tfmin->x_map ();
    _ttim2 = new X_textip (this, this, &Tst1, 100, 106,  80, 17, 256, _tfmin);
    _ttim2->set_text ("10");
    _ttim2->x_map ();
    _tfmax = new X_textip (this, this, &Tst1, 100, 130,  80, 17, 256, _ttim2);
    _tfmax->set_text ("20e3");
    _tfmax->x_map ();
    _ttim3 = new X_textip (this, this, &Tst1, 100, 154,  80, 17, 256, _tfmax);
    _ttim3->set_text ("0.03");
    _ttim3->x_map ();
    Bst0.size.x = 36;
    Bst0.size.y = 18;
    _blin = new X_tbutton (this, this,  &Bst0, 240, 106, "Lin", 0, B_LIN);
    _blin->x_map ();
    _blog = new X_tbutton (this, this,  &Bst0, 277, 106, "Log", 0, B_LOG);
    _blog->set_stat (2);
    _blog->x_map ();
    Bst0.size.x = 54;
    Bst0.size.y = 18;
    _bsgen = new X_tbutton (this, this,  &Bst0, 355, 130, "Create", 0, B_SGEN);
    _bsgen->set_stat (2);
    _bsgen->x_map ();   
    _bcanc = new X_tbutton (this, this,  &Bst0, 355, 154, "Close", 0, B_CANC);
    _bcanc->set_stat (1);
    _bcanc->x_map ();   
    add_text ( 10,  10, 80, 17, "Name", 1);
    add_text ( 10,  34, 80, 17, "Rate", 1);
    add_text ( 10,  58, 80, 17, "Fade in", 1);
    add_text ( 10,  82, 80, 17, "Start freq", 1);
    add_text ( 10, 106, 80, 17, "Sweep time", 1);
    add_text ( 10, 130, 80, 17, "End freq", 1);
    add_text ( 10, 154, 80, 17, "Fade out", 1);
    add_text (185, 106, 45, 17, "Type", 1);
    
    _sess = ".";
}


Sgenwin::~Sgenwin (void)
{
}


void Sgenwin::handle_callb (int type, X_window *W, _XEvent *E)
{
    switch (type)
    {
    case TEXTIP | X_textip::BUT:
        XSetInputFocus (dpy (), W->win (), RevertToPointerRoot, CurrentTime);
        _ready->x_unmap ();
	break;

    case TEXTIP | X_textip::KEY:
	break;

    case BUTTON | X_button::RELSE:
    {
        X_button *B = (X_button *) W;
	switch (B->cbid ())
        {
        case B_LIN:
            _blin->set_stat (2);
            _blog->set_stat (0);
            _ready->x_unmap ();
	    break;
        
        case B_LOG:
            _blin->set_stat (0);
            _blog->set_stat (2);
            _ready->x_unmap ();
	    break;
        
        case B_CANC:
            hide ();
	    break;

        case B_SGEN:
            gensweep ();
	    break;
	}
        break;
    }
    }
}


void Sgenwin::handle_event (XEvent *E)
{
    switch (E->type)
    {
    case ClientMessage:
        xcmesg ((XClientMessageEvent *) E);
        break;
    }
}


void Sgenwin::xcmesg (XClientMessageEvent *E)
{
    if (E->message_type == _xatom) hide ();
}


void Sgenwin::show (void)
{
    char s [64];

    sprintf (s, "%d", _rate);
    _trate->set_text (s);
    _tname->set_text ("");
    _ready->x_unmap ();
    x_mapraised ();
}


void Sgenwin::hide (void)
{
    x_unmap ();
}


void Sgenwin::add_text (int xp, int yp, int xs, int ys, const char *text, int align)
{
    (new X_textln (this, &Tst0, xp, yp, xs, ys, text, align))->x_map ();
}


void Sgenwin::askdata (X_textip *T)
{
    T->set_text ("???");
    XSetInputFocus (dpy (), T->win (), RevertToPointerRoot, CurrentTime);
}


void Sgenwin::gensweep (void)
{
    int   rate, k;
    char  name [64];
    char  path [1024];
    float t0, t1, t2;

    if ((sscanf (_tname->text (), "%s", name) != 1) || (*name == '?'))
    {
	askdata (_tname);
        return;
    }
    if ((sscanf (_trate->text (), "%d", &rate) != 1) || (rate < 8000) || (rate > 96000)) 
    {
	askdata (_trate);
        return;
    }
    _rate = rate;
    if ((sscanf (_ttim1->text (), "%f", &t0) != 1) || (t0 < 0.0) || (t0 > 1.0f)) 
    {
	askdata (_ttim1);
        return;
    }
    if ((sscanf (_tfmin->text (), "%f", &_fmin) != 1) || (_fmin < 1.0f) || (_fmin > 0.25f * rate)) 
    {
	askdata (_tfmin);
        return;
    }
    if ((sscanf (_ttim2->text (), "%f", &t1) != 1) || (t1 < 1.0f) || (t1 > 100.0f)) 
    {
	askdata (_ttim2);
        return;
    }
    if ((sscanf (_tfmax->text (), "%f", &_fmax) != 1) || (_fmax < 2 * _fmin) || (_fmax > 0.50f *rate)) 
    {
	askdata (_tfmax);
        return;
    }
    if ((sscanf (_ttim3->text (), "%f", &t2) != 1) || (t2 < 0.0f) || (t2 > 1.0f)) 
    {
	askdata (_ttim3);
        return;
    }

    _k0 = (int)(t0 * rate);
    _k1 = (int)(t1 * rate);
    _k2 = (int)(t2 * rate);
    k = _k0 + _k1 + _k2;

    sprintf (path, "%s/sweep/%s", _sess, name);
    Impdata::checkext (path);
    _impd.set_type (Impdata::TYPE_SWEEP);
    _impd.set_rate (rate, 1);
    _impd.set_n_sect (1);
    _impd.set_n_fram (k);
    _impd.alloc ();
    if (_impd.open_write (path))
    {
	fprintf (stderr, "Can't create '%s'\n", path);
        return;
    }
    if (_blog->stat ()) genlogsweep ();
    else                genlinsweep ();
    _impd.write_sect (0);
    _impd.close ();
    _impd.deall ();
    _ready->x_map ();
}


void Sgenwin::genlogsweep (void)
{
    int     i;
    double  a, b, g, q, q0, p, r, x;
    float   *s1, *s2;

    b = log (_fmax / _fmin) / _k1;
    a = _fmin / (b * _rate);
    r = 0.5 * a * (_fmax / _fmin) * (_k1 + 0.5 * (_k0 + _k2)) / (b * _k1);
    s1 = _impd.data (0);
    s2 = _impd.data (1) + 2 * (_impd.n_fram () - 1);
    q0 = a * exp (-b * _k0);
    for (i = -_k0; i < _k1 + _k2; i++)
    {
        if      (i < 0)   g = cos (0.5 * M_PI * i / _k0);
        else if (i < _k1) g = 1.0;
        else              g = sin (0.5 * M_PI * (_k1 + _k2 - i) / _k2);
	q = a * exp (b * i);
        p = q - q0;
	x = g * sin (2 * M_PI * (p - floor (p)));
	*s1 = (float)(x);
        *s2 = (float)(x * q / r);
        s1 += 2;
        s2 -= 2;
    }
}


void Sgenwin::genlinsweep (void)
{
    int     i;
    double  a, b, g, p, r, x;
    float   *s1, *s2;

    a = _fmin / _rate;
    b = (_fmax - _fmin) / (2.0 * _rate * _k1);
    r = 2.0 / (_k1 + 0.5 * (_k0 + _k2));
    s1 = _impd.data (0);
    s2 = _impd.data (1) + 2 * (_impd.n_fram () - 1);

    for (i = 0; i < _k0 + _k1 + _k2; i++)
    {
        if      (i < _k0)       g = sin (0.5 * M_PI * i / _k0);
        else if (i < _k0 + _k1) g = 1.0;
        else                    g = sin (0.5 * M_PI * (_k0 + _k1 + _k2 - i) / _k2);
        p = i * (a + b * i);
	x = g * sin (2 * M_PI * (p - floor (p)));
	*s1 = (float)(x);
        *s2 = (float)(x * r);
        s1 += 2;
        s2 -= 2;
    }
}
