// generated by Fast Light User Interface Designer (fluid) version 1.0308

#include "FilterUI.h"
// FilterUI.cc
// Original ZynAddSubFX author Nasca Octavian Paul
// Copyright (C) 2002-2005 Nasca Octavian Paul
// Copyright 2009-2011, Alan Calvert
// Copyright 2016-2022 Will Godfrey

// This file is part of yoshimi, which 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.

// yoshimi 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 (version 2 or
// later) for more details.

// You should have received a copy of the GNU General Public License along with
// yoshimi; if not, write to the Free Software Foundation, Inc., 51 Franklin
// Street, Fifth Floor, Boston, MA  02110-1301, USA.

// This file is derivative of ZynAddSubFX original code


#include <FL/Fl.H>
#include <FL/names.h>
#include "MasterUI.h"
#include "Misc/FormatFuncs.h"
    using func::asString;
#include "Misc/NumericFuncs.h"
    using func::asDecibel;
    using func::limit;

FormantFilterGraph::FormantFilterGraph(int x, int y, int w, int h, FilterUI& parent_,
            FilterParams *pars_, int *nvowel_, int *nformant_):
      Fl_Box(x,y,w,h), parent(parent_), pars(pars_), nvowel(nvowel_), nformant(nformant_) {
  //
          selectedFormant = -1;
          hoverFormant = -1;
          qMode = false;
          graphpoints = new float [w];
}

void FormantFilterGraph::draw_freq_line(float freq) {
  //
          float freqx = pars->getfreqpos(freq);
          if (freqx > 0.0 && freqx < 1.0)
              fl_line(x() + (int) (freqx * w()), y(), x() + (int)(freqx * w()), y() + h());
}

void FormantFilterGraph::draw() {
  //
          int maxdB = 30;
          int ox = x(), oy = y(), lx = w(), ly = h(), i, oiy;
          float freqx;
  
          int points = 475;
          float scale = lx / float(points);
          fl_line_style(0, 1 * scale); // part of new resizable code
  
          fl_color(FL_BLACK);
          fl_rectf(ox, oy, lx, ly);
  
          //draw the lines
          fl_color(FL_GRAY);
  
          freqx = pars->getfreqpos(1000.0);
          if (freqx > 0.0 && freqx < 1.0)
              fl_line(ox + (int)(freqx * lx), oy, ox + (int)(freqx * lx), oy + ly);
  
          for (i = 1; i < 10; ++i)
          {
              if (i == 1)
              {
                  draw_freq_line(i * 100.0);
                  draw_freq_line(i * 1000.0);
              }
              else if (i == 5)
              {
                  draw_freq_line(i * 100.0);
                  draw_freq_line(i * 1000.0);
              }
              else
              {
                  draw_freq_line(i * 100.0);
                  draw_freq_line(i * 1000.0);
              }
          }
  
          draw_freq_line(10000.0);
          draw_freq_line(20000.0);
  
          int GY = 10;
          if (ly < GY * 3 )
              GY = -1;
          for (i = 1; i < GY; ++i)
          {
              int tmp = (int)(ly / (float)GY * i);
              fl_line(ox + 2, oy + tmp, ox + lx - 2, oy + tmp);
          }
  
          fl_line_style(0, 2 * scale);
          fl_color(FL_YELLOW);
          fl_font(FL_HELVETICA, 10 * scale);
          if (*nformant < pars->Pnumformants)
          {
              draw_freq_line(pars->getformantfreq(pars->Pvowels[*nvowel].formants[*nformant].freq));
  
              //show some information (like current formant frequency,amplitude)
              string tmpstr = asString((float)
                  (pars->getformantfreq(pars->Pvowels[*nvowel].formants[*nformant].freq) / 1000.0))
                      + " kHz";
              fl_draw(tmpstr.c_str(), ox + 2 * scale, oy + 2 * scale, 40 * scale, 12 * scale, FL_ALIGN_LEFT, NULL, 0);
              tmpstr = asString((int)
                  (asDecibel(1e-9 + pars->getformantamp(pars->Pvowels[*nvowel].formants[*nformant].amp)) + pars->getgain()))
                            + " dB";
              fl_draw(tmpstr.c_str(), ox + 2 * scale, oy + 15 * scale, 40 * scale, 12 * scale, FL_ALIGN_LEFT, NULL, 0);
          }
  
          if (hoverFormant >= 0 && hoverFormant != *nformant)
          {
              fl_color(fl_darker(FL_YELLOW));
              draw_freq_line(pars->getformantfreq(pars->Pvowels[*nvowel].formants[hoverFormant].freq));
          }
  
          // draw the data
          fl_color(FL_RED);
  
          pars->formantfilterH(*nvowel, points, graphpoints);
  
          int lastpos = ox;
          oiy = (int) ((graphpoints[0] / maxdB + 1.0) * ly / 2.0);
          for (i = 1; i < points; ++i)
          {
              int nextpos = ox + int(i * scale);
              int iy = (int) ((graphpoints[i] / maxdB + 1.0) * ly / 2.0);
              if (iy >= 0 && oiy >= 0 && iy < ly && oiy < lx)
                  fl_line(lastpos, oy + ly - oiy, nextpos, oy + ly - iy);
              oiy = iy;
              lastpos = nextpos;
          }
          parent.formantRtext();
          fl_line_style(0,1);
  
          /*  original version
  
          pars->formantfilterH(*nvowel, lx, graphpoints);
  
          oiy = (int) ((graphpoints[0] / maxdB + 1.0) * ly / 2.0);
          for (i = 1; i < lx; ++i)
          {
              int iy = (int) ((graphpoints[i] / maxdB + 1.0) * ly / 2.0);
              if (iy >= 0 && oiy >= 0 && iy < ly && oiy < lx)
                  fl_line(ox + i - 1, oy + ly - oiy, ox, oy + ly - iy);
              oiy = iy;
          }
          */
}

FormantFilterGraph::~FormantFilterGraph() {
  delete [] graphpoints;
}

int FormantFilterGraph::handle(int event) {
  //
  switch(event)
  {
    case FL_ENTER: // enable keyboard and drag events
        Fl::focus(this);
        Fl::belowmouse(this);
        fl_cursor(FL_CURSOR_HAND);
        return 1;
    case FL_MOVE: // find formant closest to cursor
    {
        int minDiff = INT_MAX;
        int relPos = (int)(127.0f * ((float) Fl::event_x() / w()));
        for (int i = 0; i < pars->Pnumformants; ++i)
        {
            int diff = abs(pars->Pvowels[*nvowel].formants[i].freq - relPos);
            if (diff < minDiff)
            {
                minDiff = diff;
                hoverFormant = i;
            }
        }
        redraw();
        return 1;
    }
    case FL_PUSH:
        if (Fl::event_key() > FL_Button + FL_RIGHT_MOUSE)
        {
            handle(FL_KEYDOWN); // Non-LMB/MMB/RMB button - check for forward/backward
            return 0;
        }
  
        Fl::pushed(this);
  
         // select formant closest to cursor
        if (selectedFormant < 0 && Fl::event_button() != FL_MIDDLE_MOUSE)
        {
            selectedFormant = hoverFormant;
            delegate(parent.formantnumber, hoverFormant);
            hoverFormant = -1;
        }
  
        //Activate w. RMB, retain state when using MMB
        qMode = Fl::event_button() == FL_RIGHT_MOUSE
            || (Fl::event_button() == FL_MIDDLE_MOUSE && qMode);
  
        update_refs();
  
        return 1;
    case FL_DRAG: // change frequency/amplitude/q for selected formant
    {
  
        int hDiff = 127 * (xRef - Fl::event_x()) / w();
        int vDiff = 127 * (yRef - Fl::event_y()) / h();
  
        if (Fl::event_button2()) // Always prioritize center frequency changes
        {
            fl_cursor(FL_CURSOR_WE);
            delegate(parent.cfknob, limit(cFreqRef + hDiff, 0, 127));
        }
        else
        {
           fl_cursor(FL_CURSOR_MOVE);
            delegate(parent.formant_freq_dial, limit(freqRef - hDiff, 0, 127));
  
            if (qMode)
                delegate(parent.formant_q_dial, limit(qRef + vDiff, 0, 127));
            else
                delegate(parent.formant_amp_dial, limit(ampRef + vDiff, 0, 127));
        }
        return 1;
    }
    case FL_KEYDOWN: // changes active vowel with left/right , x/z, or forward/back mouse buttons
  
        if (Fl::event_key(FL_Left) || Fl::event_key(122) || Fl::event_key() == FL_Button + 8)
        {
            delegate(parent.vowelnumber, (FF_MAX_VOWELS + ((*nvowel) - 1)) % FF_MAX_VOWELS);
            hoverFormant = -1;
        }
        else if (Fl::event_key(FL_Right) || Fl::event_key(120) || Fl::event_key() == FL_Button + 9)
        {
            delegate(parent.vowelnumber, ((*nvowel) + 1) % FF_MAX_VOWELS);
            hoverFormant = -1;
        }
        return 1;
    case FL_MOUSEWHEEL:
    {
        int offset = Fl::event_dy() * (Fl::event_ctrl() ? 1 : 4);
        if (Fl::event_shift())
            delegate(parent.cfknob, limit(pars->Pcenterfreq + offset, 0, 127));
        else
            delegate(parent.octknob, limit(pars->Poctavesfreq + offset, 0, 127));
        return 1;
    }
    case FL_RELEASE:
  
        if (Fl::event_inside(this))
            fl_cursor(FL_CURSOR_HAND);
  
        if (Fl::event_button() == FL_RIGHT_MOUSE)
            qMode = false;
        else if (Fl::event_button() == FL_LEFT_MOUSE)
            qMode = true;
  
        if (!Fl::event_button1() && !Fl::event_button3())
        {
            selectedFormant = -1;
            return 1;
        }
        else
        {
            update_refs();
        }
        Fl::pushed(this);
        return 1;
    case FL_LEAVE:
        if (!Fl::event_inside(this)) // Cover for some strange events when clicking
        {
            hoverFormant = -1;
            qMode = false;
            redraw();
            fl_cursor(FL_CURSOR_DEFAULT);
        }
        return 1;
  }
  
  return Fl_Box::handle(event);
}

void FormantFilterGraph::delegate(Fl_Valuator* w, int value) {
  // If widget value has changed, update and perform manual callback
  
          if (w->value() != value)
          {
              w->value(value);
              w->do_callback();
          }
}

inline void FormantFilterGraph::update_refs() {
  //
          yRef = Fl::event_y();
          xRef = Fl::event_x();
          ampRef = pars->Pvowels[*nvowel].formants[selectedFormant].amp;
          freqRef = pars->Pvowels[*nvowel].formants[selectedFormant].freq;
          qRef = pars->Pvowels[*nvowel].formants[selectedFormant].q;
          cFreqRef = pars->Pcenterfreq;
}

void FilterUI::cb_analogfiltertypechoice_i(Fl_Choice* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::analogType, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_analogfiltertypechoice(Fl_Choice* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_analogfiltertypechoice_i(o,v);
}

void FilterUI::cb_svfiltertypechoice_i(Fl_Choice* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::stateVariableType, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_svfiltertypechoice(Fl_Choice* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_svfiltertypechoice_i(o,v);
}

void FilterUI::cb_filtertype_i(Fl_Choice* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::baseType, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_filtertype(Fl_Choice* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_filtertype_i(o,v);
}

void FilterUI::cb_cfreqdial_i(WidgetPDial* o, void*) {
  //
          send_data(0, FILTERINSERT::control::centerFrequency, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_cfreqdial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_cfreqdial_i(o,v);
}

void FilterUI::cb_qdial_i(WidgetPDial* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::Q, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_qdial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_qdial_i(o,v);
}

void FilterUI::cb_freqtrdial_i(WidgetPDial* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::frequencyTracking, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_freqtrdial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_freqtrdial_i(o,v);
}

void FilterUI::cb_vsnsadial_i(WidgetPDial* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::velocitySensitivity, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_vsnsadial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_vsnsadial_i(o,v);
}

void FilterUI::cb_vsnsdial_i(WidgetPDial* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::velocityCurve, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_vsnsdial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_vsnsdial_i(o,v);
}

void FilterUI::cb_gaindial_i(WidgetPDial* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::gain, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_gaindial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_gaindial_i(o,v);
}

void FilterUI::cb_stcounter_i(Fl_Counter* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::stages, o->value() - 1, TOPLEVEL::type::Write);
}
void FilterUI::cb_stcounter(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_stcounter_i(o,v);
}

void FilterUI::cb_editbutton_i(Fl_Button*, void*) {
  //
    int X, Y, W, H, O;
    int type = engine;
    if (type > 2)
        type = 3;
    //std::cout << "type open " << type << std::endl;
    loadWin(synth, W, H, X, Y, O, "xFilter-formant " + std::to_string(type));
    if (W < formantDW || H < formantDH)
    {
        W = formantDW;
        H = formantDH;
    }
    checkSane(X, Y, W, H , formantDW, formantDH);
    formantparswindow->resize(X, Y, W, H);
    lastformantX = 0;
    lastformantY = 0;
    lastformantW = 0;
    formantSeen = true;
    formantRtext();
    formantparswindow->show();
}
void FilterUI::cb_editbutton(Fl_Button* o, void* v) {
  ((FilterUI*)(o->parent()->user_data()))->cb_editbutton_i(o,v);
}

void FilterUI::cb_filtC_i(Fl_Button*, void*) {
  synth->getGuiMaster()->getPresetsUi()->copy(pars);
}
void FilterUI::cb_filtC(Fl_Button* o, void* v) {
  ((FilterUI*)(o->parent()->user_data()))->cb_filtC_i(o,v);
}

void FilterUI::cb_filtP_i(Fl_Button*, void*) {
  synth->getGuiMaster()->getPresetsUi()->paste(pars,this);
}
void FilterUI::cb_filtP(Fl_Button* o, void* v) {
  ((FilterUI*)(o->parent()->user_data()))->cb_filtP_i(o,v);
}

void FilterUI::cb_freqtrackoffset_i(Fl_Check_Button2* o, void*) {
  //
        int tmp = (o->value() != 0);
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::frequencyTrackingRange, tmp, TOPLEVEL::type::Write);
}
void FilterUI::cb_freqtrackoffset(Fl_Check_Button2* o, void* v) {
  ((FilterUI*)(o->parent()->user_data()))->cb_freqtrackoffset_i(o,v);
}

void FilterUI::cb_formantparswindow_i(Fl_Double_Window*, void*) {
  formClose->do_callback();
}
void FilterUI::cb_formantparswindow(Fl_Double_Window* o, void* v) {
  ((FilterUI*)(o->user_data()))->cb_formantparswindow_i(o,v);
}

void FilterUI::cb_formantnumber_i(Fl_Counter* o, void*) {
  //
          nformant = (int) o->value();
          update_formant_window();
          formantfiltergraph->redraw();
          //send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantNumber, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_formantnumber(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_formantnumber_i(o,v);
}

void FilterUI::cb_vowelnumber_i(Fl_Counter* o, void*) {
  //
          nvowel = (int) o->value();
          update_formant_window();
          formantfiltergraph->redraw();
          //send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::vowelNumber, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_vowelnumber(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_vowelnumber_i(o,v);
}

void FilterUI::cb_formant_freq_dial_i(WidgetPDial* o, void*) {
  //
            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantFrequency, o->value(), TOPLEVEL::type::Write, nformant, nvowel);
}
void FilterUI::cb_formant_freq_dial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->parent()->user_data()))->cb_formant_freq_dial_i(o,v);
}

void FilterUI::cb_formant_q_dial_i(WidgetPDial* o, void*) {
  //
            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantQ, o->value(), TOPLEVEL::type::Write, nformant, nvowel);
}
void FilterUI::cb_formant_q_dial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->parent()->user_data()))->cb_formant_q_dial_i(o,v);
}

void FilterUI::cb_formant_amp_dial_i(WidgetPDial* o, void*) {
  //
            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantAmplitude, o->value(), TOPLEVEL::type::Write, nformant, nvowel);
}
void FilterUI::cb_formant_amp_dial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->parent()->user_data()))->cb_formant_amp_dial_i(o,v);
}

void FilterUI::cb_seqsize_i(Fl_Counter* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::sequenceSize, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_seqsize(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_seqsize_i(o,v);
}

void FilterUI::cb_seqpos_i(Fl_Counter* o, void*) {
  //
          nseqpos = (int) o->value();
          update_formant_window();
          send_data(0, FILTERINSERT::control::sequencePosition, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_seqpos(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_seqpos_i(o,v);
}

void FilterUI::cb_vowel_counter_i(Fl_Counter* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::vowelPositionInSequence, o->value(), TOPLEVEL::type::Write, nseqpos);
}
void FilterUI::cb_vowel_counter(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_vowel_counter_i(o,v);
}

void FilterUI::cb_neginput_i(Fl_Check_Button2* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::negateInput, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_neginput(Fl_Check_Button2* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_neginput_i(o,v);
}

void FilterUI::cb_strchdial_i(WidgetPDial* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantStretch, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_strchdial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->parent()->user_data()))->cb_strchdial_i(o,v);
}

void FilterUI::cb_formantcount_i(Fl_Counter* o, void*) {
  //
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::numberOfFormants, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_formantcount(Fl_Counter* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_formantcount_i(o,v);
}

void FilterUI::cb_frsldial_i(WidgetPDial* o, void*) {
  //
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantSlowness, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_frsldial(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_frsldial_i(o,v);
}

void FilterUI::cb_centerfreqvo_i(Fl_Value_Output* o, void*) {
  o->value(pars->getcenterfreq()/1000.0);
}
void FilterUI::cb_centerfreqvo(Fl_Value_Output* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_centerfreqvo_i(o,v);
}

void FilterUI::cb_octavesfreqvo_i(Fl_Value_Output* o, void*) {
  o->value(pars->getoctavesfreq());
}
void FilterUI::cb_octavesfreqvo(Fl_Value_Output* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_octavesfreqvo_i(o,v);
}

void FilterUI::cb_cfknob_i(mwheel_slider_rev* o, void*) {
  //
        if (Fl::event_button() == 3)
            o->value(64);
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantCenter, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_cfknob(mwheel_slider_rev* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_cfknob_i(o,v);
}

void FilterUI::cb_octknob_i(mwheel_slider_rev* o, void*) {
  //
        if (Fl::event_button() == 3)
            o->value(64);
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantOctave, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_octknob(mwheel_slider_rev* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_octknob_i(o,v);
}

void FilterUI::cb_wvknob_i(WidgetPDial* o, void*) {
  //
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantClearness, o->value(), TOPLEVEL::type::Write);
}
void FilterUI::cb_wvknob(WidgetPDial* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_wvknob_i(o,v);
}

void FilterUI::cb_formClose_i(Fl_Button*, void*) {
  //
    int type = engine;
    if (engine > 2)
        type = 3;
    //std::cout << "type close " << type << std::endl;
    if (formantSeen)
        saveWin(synth, formantparswindow->w(), formantparswindow->h(), formantparswindow->x(), formantparswindow->y(), false, "xFilter-formant " +std::to_string(type));
    formantSeen = false,
    formantparswindow->hide();
    lastformantW = 0;
}
void FilterUI::cb_formClose(Fl_Button* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_formClose_i(o,v);
}

void FilterUI::cb_formCopy_i(Fl_Button*, void*) {
  synth->getGuiMaster()->getPresetsUi()->copy(pars,nvowel);
}
void FilterUI::cb_formCopy(Fl_Button* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_formCopy_i(o,v);
}

void FilterUI::cb_formPaste_i(Fl_Button*, void*) {
  synth->getGuiMaster()->getPresetsUi()->paste(pars,this,nvowel);
}
void FilterUI::cb_formPaste(Fl_Button* o, void* v) {
  ((FilterUI*)(o->parent()->parent()->user_data()))->cb_formPaste_i(o,v);
}

FilterUI::FilterUI(int x,int y, int w, int h, const char *label):Fl_Group(x,y,w,h,label) {
  //
          synth = NULL;
          pars=NULL;
          velsnsamp=NULL;
          velsns=NULL;
          nvowel = 0;
          nformant = 0;
          nseqpos = 0;
}

FilterUI::~FilterUI() {
  filterui->hide();
          formantparswindow->hide();
          hide();
          delete (formantparswindow);
}

Fl_Group* FilterUI::make_window() {
  { filterui = new Fl_Group(0, 0, 275, 75);
    filterui->box(FL_FLAT_BOX);
    filterui->color((Fl_Color)247);
    filterui->selection_color(FL_BACKGROUND_COLOR);
    filterui->labeltype(FL_NO_LABEL);
    filterui->labelfont(1);
    filterui->labelsize(12);
    filterui->labelcolor(FL_FOREGROUND_COLOR);
    filterui->user_data((void*)(this));
    filterui->align(Fl_Align(FL_ALIGN_TOP));
    filterui->when(FL_WHEN_RELEASE);
    { filterparamswindow = new Fl_Group(0, 0, 275, 75);
      filterparamswindow->box(FL_PLASTIC_UP_BOX);
      filterparamswindow->color((Fl_Color)231);
      filterparamswindow->labelfont(1);
      filterparamswindow->labelsize(10);
      filterparamswindow->align(Fl_Align(FL_ALIGN_TOP|FL_ALIGN_INSIDE));
      { Fl_Choice* o = analogfiltertypechoice = new Fl_Choice(5, 43, 58, 15, "FilterType");
        analogfiltertypechoice->tooltip("The Filter type");
        analogfiltertypechoice->down_box(FL_BORDER_BOX);
        analogfiltertypechoice->labelsize(10);
        analogfiltertypechoice->textfont(1);
        analogfiltertypechoice->textsize(10);
        analogfiltertypechoice->callback((Fl_Callback*)cb_analogfiltertypechoice);
        analogfiltertypechoice->align(Fl_Align(FL_ALIGN_BOTTOM_LEFT));
        o->value(pars->Ptype);
        o->add("Low1");o->add("High1");o->add("Low2");o->add("High2");o->add("Band2");o->add("Stop2");o->add("Peak2");o->add("LShelf2");o->add("HShelf2");
      } // Fl_Choice* analogfiltertypechoice
      { Fl_Choice* o = svfiltertypechoice = new Fl_Choice(5, 43, 58, 15, "FilterType");
        svfiltertypechoice->tooltip("The Filter type");
        svfiltertypechoice->down_box(FL_BORDER_BOX);
        svfiltertypechoice->labelsize(10);
        svfiltertypechoice->textfont(1);
        svfiltertypechoice->textsize(10);
        svfiltertypechoice->callback((Fl_Callback*)cb_svfiltertypechoice);
        svfiltertypechoice->align(Fl_Align(FL_ALIGN_BOTTOM_LEFT));
        o->value(pars->Ptype);
        o->add("Low");o->add("High");o->add("Band");o->add("Stop");
      } // Fl_Choice* svfiltertypechoice
      { Fl_Choice* o = filtertype = new Fl_Choice(5, 10, 66, 15, "Category");
        filtertype->tooltip("The Category of the Filter (Analog/Formantic/etc.)");
        filtertype->down_box(FL_BORDER_BOX);
        filtertype->labelsize(10);
        filtertype->textfont(1);
        filtertype->textsize(10);
        filtertype->callback((Fl_Callback*)cb_filtertype);
        filtertype->align(Fl_Align(FL_ALIGN_BOTTOM_LEFT));
        o->value(pars->Pcategory);
        o->add("analog");o->add("formant");o->add("StVarF");
      } // Fl_Choice* filtertype
      { WidgetPDial* o = cfreqdial = new WidgetPDial(65, 28, 30, 30, " C.Freq");
        cfreqdial->tooltip("Center Frequency of the Filter or the base position in the vowel\'s sequence");
        cfreqdial->box(FL_ROUND_UP_BOX);
        cfreqdial->color(FL_BACKGROUND_COLOR);
        cfreqdial->selection_color(FL_INACTIVE_COLOR);
        cfreqdial->labeltype(FL_NORMAL_LABEL);
        cfreqdial->labelfont(0);
        cfreqdial->labelsize(10);
        cfreqdial->labelcolor(FL_FOREGROUND_COLOR);
        cfreqdial->maximum(127);
        cfreqdial->step(1);
        cfreqdial->callback((Fl_Callback*)cb_cfreqdial);
        cfreqdial->align(Fl_Align(FL_ALIGN_BOTTOM));
        cfreqdial->when(FL_WHEN_CHANGED);
        o->value(pars->Pfreq);
        o->setValueType(getFilterFreqType(filtertype->value()));
      } // WidgetPDial* cfreqdial
      { WidgetPDial* o = qdial = new WidgetPDial(100, 28, 30, 30, "Q");
        qdial->tooltip("Filter resonance or bandwidth");
        qdial->box(FL_ROUND_UP_BOX);
        qdial->color(FL_BACKGROUND_COLOR);
        qdial->selection_color(FL_INACTIVE_COLOR);
        qdial->labeltype(FL_NORMAL_LABEL);
        qdial->labelfont(0);
        qdial->labelsize(10);
        qdial->labelcolor(FL_FOREGROUND_COLOR);
        qdial->maximum(127);
        qdial->step(1);
        qdial->callback((Fl_Callback*)cb_qdial);
        qdial->align(Fl_Align(FL_ALIGN_BOTTOM));
        qdial->when(FL_WHEN_CHANGED);
        o->value(pars->Pq);
        updateVCforQ();
      } // WidgetPDial* qdial
      { WidgetPDial* o = freqtrdial = new WidgetPDial(240, 28, 30, 30, "Freq.tr.");
        freqtrdial->tooltip("Filter frequency tracking");
        freqtrdial->box(FL_ROUND_UP_BOX);
        freqtrdial->color(FL_BACKGROUND_COLOR);
        freqtrdial->selection_color(FL_INACTIVE_COLOR);
        freqtrdial->labeltype(FL_NORMAL_LABEL);
        freqtrdial->labelfont(0);
        freqtrdial->labelsize(10);
        freqtrdial->labelcolor(FL_FOREGROUND_COLOR);
        freqtrdial->maximum(127);
        freqtrdial->step(1);
        freqtrdial->callback((Fl_Callback*)cb_freqtrdial);
        freqtrdial->align(Fl_Align(FL_ALIGN_BOTTOM));
        freqtrdial->when(FL_WHEN_CHANGED);
        o->value(pars->Pfreqtrack);
      } // WidgetPDial* freqtrdial
      { WidgetPDial* o = vsnsadial = new WidgetPDial(135, 28, 30, 30, "V.Sns.");
        vsnsadial->tooltip("Velocity sensing amount of the Filter");
        vsnsadial->box(FL_ROUND_UP_BOX);
        vsnsadial->color(FL_BACKGROUND_COLOR);
        vsnsadial->selection_color(FL_INACTIVE_COLOR);
        vsnsadial->labeltype(FL_NORMAL_LABEL);
        vsnsadial->labelfont(0);
        vsnsadial->labelsize(10);
        vsnsadial->labelcolor(FL_FOREGROUND_COLOR);
        vsnsadial->maximum(127);
        vsnsadial->step(1);
        vsnsadial->callback((Fl_Callback*)cb_vsnsadial);
        vsnsadial->align(Fl_Align(FL_ALIGN_BOTTOM));
        vsnsadial->when(FL_WHEN_CHANGED);
        o->setValueType(VC_FilterVelocityAmp);
      } // WidgetPDial* vsnsadial
      { WidgetPDial* o = vsnsdial = new WidgetPDial(170, 28, 30, 30, " VF.Sns.");
        vsnsdial->tooltip("Velocity Sensing Function of the Filter");
        vsnsdial->box(FL_ROUND_UP_BOX);
        vsnsdial->color(FL_BACKGROUND_COLOR);
        vsnsdial->selection_color(FL_INACTIVE_COLOR);
        vsnsdial->labeltype(FL_NORMAL_LABEL);
        vsnsdial->labelfont(0);
        vsnsdial->labelsize(10);
        vsnsdial->labelcolor(FL_FOREGROUND_COLOR);
        vsnsdial->maximum(127);
        vsnsdial->step(1);
        vsnsdial->callback((Fl_Callback*)cb_vsnsdial);
        vsnsdial->align(Fl_Align(FL_ALIGN_BOTTOM));
        vsnsdial->when(FL_WHEN_CHANGED);
        o->setValueType(VC_FilterVelocitySense);
        o->setGraphicsType(VC_FilterVelocitySense);
      } // WidgetPDial* vsnsdial
      { WidgetPDial* o = gaindial = new WidgetPDial(205, 28, 30, 30, "Gain");
        gaindial->tooltip("Filter output gain/damp");
        gaindial->box(FL_ROUND_UP_BOX);
        gaindial->color(FL_BACKGROUND_COLOR);
        gaindial->selection_color(FL_INACTIVE_COLOR);
        gaindial->labeltype(FL_NORMAL_LABEL);
        gaindial->labelfont(0);
        gaindial->labelsize(10);
        gaindial->labelcolor(FL_FOREGROUND_COLOR);
        gaindial->maximum(127);
        gaindial->step(1);
        gaindial->callback((Fl_Callback*)cb_gaindial);
        gaindial->align(Fl_Align(FL_ALIGN_BOTTOM));
        gaindial->when(FL_WHEN_CHANGED);
        o->value(pars->Pgain);
        o->setValueType(VC_FilterGain);
      } // WidgetPDial* gaindial
      { stcounter = new Fl_Counter(78, 10, 31, 15, "St.");
        stcounter->tooltip("Filter stages (in order to increase dB/oct. value and the order of the filter\
)");
        stcounter->type(1);
        stcounter->labelsize(10);
        stcounter->minimum(1);
        stcounter->maximum(5);
        stcounter->step(1);
        stcounter->value(1);
        stcounter->textfont(1);
        stcounter->textsize(10);
        stcounter->callback((Fl_Callback*)cb_stcounter);
        stcounter->align(Fl_Align(FL_ALIGN_RIGHT));
      } // Fl_Counter* stcounter
      filterparamswindow->end();
    } // Fl_Group* filterparamswindow
    { filterparamslabel = new Fl_Text_Display(135, 14, 50, 4, "Parameters");
      filterparamslabel->box(FL_NO_BOX);
      filterparamslabel->labelfont(1);
      filterparamslabel->labelsize(10);
    } // Fl_Text_Display* filterparamslabel
    { editbutton = new Fl_Button(5, 40, 52, 26, "Edit");
      editbutton->box(FL_PLASTIC_UP_BOX);
      editbutton->labelfont(1);
      editbutton->labelsize(11);
      editbutton->callback((Fl_Callback*)cb_editbutton);
    } // Fl_Button* editbutton
    { filtC = new Fl_Button(202, 8, 15, 15, "C");
      filtC->box(FL_THIN_UP_BOX);
      filtC->color((Fl_Color)179);
      filtC->labelfont(1);
      filtC->labelsize(10);
      filtC->labelcolor(FL_BACKGROUND2_COLOR);
      filtC->callback((Fl_Callback*)cb_filtC);
    } // Fl_Button* filtC
    { filtP = new Fl_Button(220, 8, 15, 15, "P");
      filtP->box(FL_THIN_UP_BOX);
      filtP->color((Fl_Color)179);
      filtP->labelfont(1);
      filtP->labelsize(10);
      filtP->labelcolor(FL_BACKGROUND2_COLOR);
      filtP->callback((Fl_Callback*)cb_filtP);
    } // Fl_Button* filtP
    { freqtrackoffset = new Fl_Check_Button2(236, 10, 16, 16);
      freqtrackoffset->tooltip("Set frequency tracking range to 0%-200%");
      freqtrackoffset->box(FL_NO_BOX);
      freqtrackoffset->down_box(FL_DOWN_BOX);
      freqtrackoffset->color(FL_BACKGROUND_COLOR);
      freqtrackoffset->selection_color(FL_FOREGROUND_COLOR);
      freqtrackoffset->labeltype(FL_NORMAL_LABEL);
      freqtrackoffset->labelfont(0);
      freqtrackoffset->labelsize(14);
      freqtrackoffset->labelcolor(FL_FOREGROUND_COLOR);
      freqtrackoffset->callback((Fl_Callback*)cb_freqtrackoffset);
      freqtrackoffset->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE));
      freqtrackoffset->when(FL_WHEN_RELEASE);
    } // Fl_Check_Button2* freqtrackoffset
    { freqtracknormal = new Fl_Text_Display(242, 24, 44, 4, "- /+");
      freqtracknormal->box(FL_NO_BOX);
      freqtracknormal->labelsize(10);
      freqtracknormal->textsize(10);
    } // Fl_Text_Display* freqtracknormal
    { freqtrackchecked = new Fl_Text_Display(242, 24, 44, 4, "0/+");
      freqtrackchecked->box(FL_NO_BOX);
      freqtrackchecked->labelsize(10);
      freqtrackchecked->textsize(10);
      freqtrackchecked->hide();
    } // Fl_Text_Display* freqtrackchecked
    filterui->end();
  } // Fl_Group* filterui
  return filterui;
}

Fl_Double_Window* FilterUI::make_formant_window() {
  { Fl_Double_Window* o = formantparswindow = new Fl_Double_Window(700, 205, "Formant Filter Parameters");
    formantparswindow->labelfont(1);
    formantparswindow->labelsize(12);
    formantparswindow->callback((Fl_Callback*)cb_formantparswindow, (void*)(this));
    { Fl_Group* o = new Fl_Group(1, 1, 698, 203);
      o->box(FL_ENGRAVED_FRAME);
      { Fl_Group* o = new Fl_Group(485, 47, 105, 113);
        o->box(FL_THIN_UP_BOX);
        { Fl_Counter* o = formantnumber = new Fl_Counter(545, 80, 40, 15, "Formant ");
          formantnumber->type(1);
          formantnumber->labelfont(1);
          formantnumber->labelsize(10);
          formantnumber->minimum(0);
          formantnumber->maximum(127);
          formantnumber->step(1);
          formantnumber->textsize(10);
          formantnumber->callback((Fl_Callback*)cb_formantnumber);
          formantnumber->align(Fl_Align(FL_ALIGN_LEFT));
          o->bounds(0,FF_MAX_FORMANTS-1);
          o->value(nformant);
        } // Fl_Counter* formantnumber
        { Fl_Counter* o = vowelnumber = new Fl_Counter(545, 55, 40, 20, "Vowel no.");
          vowelnumber->type(1);
          vowelnumber->labelfont(1);
          vowelnumber->labelsize(10);
          vowelnumber->minimum(0);
          vowelnumber->maximum(127);
          vowelnumber->step(1);
          vowelnumber->textfont(1);
          vowelnumber->textsize(11);
          vowelnumber->callback((Fl_Callback*)cb_vowelnumber);
          vowelnumber->align(Fl_Align(FL_ALIGN_LEFT));
          o->bounds(0,FF_MAX_VOWELS-1);
          o->value(nvowel);
        } // Fl_Counter* vowelnumber
        { formantparsgroup = new Fl_Group(490, 105, 95, 50);
          formantparsgroup->box(FL_ENGRAVED_FRAME);
          { formant_freq_dial = new WidgetPDial(495, 115, 25, 25, "Freq");
            formant_freq_dial->tooltip("Formant frequency");
            formant_freq_dial->box(FL_ROUND_UP_BOX);
            formant_freq_dial->color(FL_BACKGROUND_COLOR);
            formant_freq_dial->selection_color(FL_INACTIVE_COLOR);
            formant_freq_dial->labeltype(FL_NORMAL_LABEL);
            formant_freq_dial->labelfont(0);
            formant_freq_dial->labelsize(10);
            formant_freq_dial->labelcolor(FL_FOREGROUND_COLOR);
            formant_freq_dial->maximum(127);
            formant_freq_dial->step(1);
            formant_freq_dial->callback((Fl_Callback*)cb_formant_freq_dial);
            formant_freq_dial->align(Fl_Align(FL_ALIGN_BOTTOM));
            formant_freq_dial->when(FL_WHEN_CHANGED);
          } // WidgetPDial* formant_freq_dial
          { formant_q_dial = new WidgetPDial(525, 115, 24, 25, "Q");
            formant_q_dial->tooltip("Formant\'s Q");
            formant_q_dial->box(FL_ROUND_UP_BOX);
            formant_q_dial->color(FL_BACKGROUND_COLOR);
            formant_q_dial->selection_color(FL_INACTIVE_COLOR);
            formant_q_dial->labeltype(FL_NORMAL_LABEL);
            formant_q_dial->labelfont(0);
            formant_q_dial->labelsize(10);
            formant_q_dial->labelcolor(FL_FOREGROUND_COLOR);
            formant_q_dial->maximum(127);
            formant_q_dial->step(1);
            formant_q_dial->callback((Fl_Callback*)cb_formant_q_dial);
            formant_q_dial->align(Fl_Align(FL_ALIGN_BOTTOM));
            formant_q_dial->when(FL_WHEN_CHANGED);
          } // WidgetPDial* formant_q_dial
          { formant_amp_dial = new WidgetPDial(555, 115, 24, 25, "Amp");
            formant_amp_dial->tooltip("Formant amplitude");
            formant_amp_dial->box(FL_ROUND_UP_BOX);
            formant_amp_dial->color(FL_BACKGROUND_COLOR);
            formant_amp_dial->selection_color(FL_INACTIVE_COLOR);
            formant_amp_dial->labeltype(FL_NORMAL_LABEL);
            formant_amp_dial->labelfont(0);
            formant_amp_dial->labelsize(10);
            formant_amp_dial->labelcolor(FL_FOREGROUND_COLOR);
            formant_amp_dial->maximum(127);
            formant_amp_dial->step(1);
            formant_amp_dial->callback((Fl_Callback*)cb_formant_amp_dial);
            formant_amp_dial->align(Fl_Align(FL_ALIGN_BOTTOM));
            formant_amp_dial->when(FL_WHEN_CHANGED);
          } // WidgetPDial* formant_amp_dial
          formantparsgroup->end();
        } // Fl_Group* formantparsgroup
        o->end();
      } // Fl_Group* o
      { Fl_Group* o = new Fl_Group(590, 47, 102, 113);
        o->box(FL_THIN_UP_BOX);
        { Fl_Counter* o = seqsize = new Fl_Counter(595, 62, 55, 20, "Seq.Size");
          seqsize->type(1);
          seqsize->labelfont(1);
          seqsize->labelsize(10);
          seqsize->minimum(0);
          seqsize->maximum(127);
          seqsize->step(1);
          seqsize->textfont(1);
          seqsize->textsize(11);
          seqsize->callback((Fl_Callback*)cb_seqsize);
          seqsize->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          o->bounds(1,FF_MAX_SEQUENCE);
          o->value(pars->Psequencesize);
        } // Fl_Counter* seqsize
        { Fl_Counter* o = seqpos = new Fl_Counter(595, 97, 40, 15, "S.Pos.");
          seqpos->tooltip("Current position in the sequence");
          seqpos->type(1);
          seqpos->labelfont(1);
          seqpos->labelsize(10);
          seqpos->minimum(0);
          seqpos->maximum(127);
          seqpos->step(1);
          seqpos->textsize(10);
          seqpos->callback((Fl_Callback*)cb_seqpos);
          seqpos->align(Fl_Align(FL_ALIGN_TOP_RIGHT));
          o->bounds(0,FF_MAX_SEQUENCE-1);
          o->value(nseqpos);
        } // Fl_Counter* seqpos
        { Fl_Counter* o = vowel_counter = new Fl_Counter(640, 97, 40, 15, "Vowel");
          vowel_counter->tooltip("Vowel number at the sequence position");
          vowel_counter->type(1);
          vowel_counter->labelsize(10);
          vowel_counter->minimum(0);
          vowel_counter->maximum(127);
          vowel_counter->step(1);
          vowel_counter->textsize(10);
          vowel_counter->callback((Fl_Callback*)cb_vowel_counter);
          vowel_counter->align(Fl_Align(FL_ALIGN_TOP));
          o->bounds(0,FF_MAX_VOWELS-1);
        } // Fl_Counter* vowel_counter
        { Fl_Check_Button2* o = neginput = new Fl_Check_Button2(625, 132, 60, 20, "Neg.Input");
          neginput->tooltip("Negate the input from LFO/envelopes/etc.");
          neginput->box(FL_NO_BOX);
          neginput->down_box(FL_DOWN_BOX);
          neginput->color(FL_BACKGROUND_COLOR);
          neginput->selection_color(FL_FOREGROUND_COLOR);
          neginput->labeltype(FL_NORMAL_LABEL);
          neginput->labelfont(0);
          neginput->labelsize(10);
          neginput->labelcolor(FL_FOREGROUND_COLOR);
          neginput->callback((Fl_Callback*)cb_neginput);
          neginput->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE));
          neginput->when(FL_WHEN_RELEASE);
          o->value(pars->Psequencereversed);
        } // Fl_Check_Button2* neginput
        { WidgetPDial* o = strchdial = new WidgetPDial(595, 130, 25, 25, "Strch");
          strchdial->tooltip("Sequence Stretch");
          strchdial->box(FL_ROUND_UP_BOX);
          strchdial->color(FL_BACKGROUND_COLOR);
          strchdial->selection_color(FL_INACTIVE_COLOR);
          strchdial->labeltype(FL_NORMAL_LABEL);
          strchdial->labelfont(0);
          strchdial->labelsize(10);
          strchdial->labelcolor(FL_FOREGROUND_COLOR);
          strchdial->maximum(127);
          strchdial->step(1);
          strchdial->callback((Fl_Callback*)cb_strchdial);
          strchdial->align(Fl_Align(FL_ALIGN_TOP));
          strchdial->when(FL_WHEN_CHANGED);
          o->value(pars->Psequencestretch);
          o->setValueType(VC_FormFilterStretch);
        } // WidgetPDial* strchdial
        o->end();
      } // Fl_Group* o
      { Fl_Counter* o = formantcount = new Fl_Counter(485, 15, 65, 20, "Formants");
        formantcount->type(1);
        formantcount->labelfont(1);
        formantcount->labelsize(10);
        formantcount->minimum(0);
        formantcount->maximum(127);
        formantcount->step(1);
        formantcount->textsize(12);
        formantcount->callback((Fl_Callback*)cb_formantcount);
        formantcount->align(Fl_Align(FL_ALIGN_TOP));
        o->bounds(1,FF_MAX_FORMANTS);
        o->value(pars->Pnumformants);
      } // Fl_Counter* formantcount
      { WidgetPDial* o = frsldial = new WidgetPDial(565, 15, 25, 25, "Fr.Sl.");
        frsldial->tooltip("Formant\'s Slowness (Morphing)");
        frsldial->box(FL_ROUND_UP_BOX);
        frsldial->color(FL_BACKGROUND_COLOR);
        frsldial->selection_color(FL_INACTIVE_COLOR);
        frsldial->labeltype(FL_NORMAL_LABEL);
        frsldial->labelfont(1);
        frsldial->labelsize(10);
        frsldial->labelcolor(FL_FOREGROUND_COLOR);
        frsldial->maximum(127);
        frsldial->step(1);
        frsldial->callback((Fl_Callback*)cb_frsldial);
        frsldial->align(Fl_Align(FL_ALIGN_TOP));
        frsldial->when(FL_WHEN_CHANGED);
        o->value(pars->Pformantslowness);
        o->setValueType(VC_FormFilterSlowness);
      } // WidgetPDial* frsldial
      { Fl_Value_Output* o = centerfreqvo = new Fl_Value_Output(512, 164, 35, 16, "C.f.");
        centerfreqvo->tooltip("Center Frequency (kHz)");
        centerfreqvo->box(FL_THIN_DOWN_BOX);
        centerfreqvo->labelsize(12);
        centerfreqvo->minimum(1);
        centerfreqvo->maximum(10);
        centerfreqvo->value(1);
        centerfreqvo->textfont(1);
        centerfreqvo->textsize(11);
        centerfreqvo->callback((Fl_Callback*)cb_centerfreqvo);
        centerfreqvo->when(3);
        o->step(0.01, 1);
        o->value(pars->getcenterfreq()/1000.0);
      } // Fl_Value_Output* centerfreqvo
      { Fl_Value_Output* o = octavesfreqvo = new Fl_Value_Output(512, 185, 35, 16, "Oct.");
        octavesfreqvo->tooltip("No. of octaves");
        octavesfreqvo->box(FL_THIN_DOWN_BOX);
        octavesfreqvo->labelsize(12);
        octavesfreqvo->minimum(1);
        octavesfreqvo->maximum(127);
        octavesfreqvo->value(5);
        octavesfreqvo->textfont(1);
        octavesfreqvo->textsize(11);
        octavesfreqvo->callback((Fl_Callback*)cb_octavesfreqvo);
        octavesfreqvo->when(3);
        o->step(0.01, 1);
        o->value(pars->getoctavesfreq());
      } // Fl_Value_Output* octavesfreqvo
      { mwheel_slider_rev* o = cfknob = new mwheel_slider_rev(547, 164, 89, 16);
        cfknob->type(5);
        cfknob->box(FL_THIN_DOWN_BOX);
        cfknob->color(FL_BACKGROUND_COLOR);
        cfknob->selection_color(FL_BACKGROUND_COLOR);
        cfknob->labeltype(FL_NORMAL_LABEL);
        cfknob->labelfont(0);
        cfknob->labelsize(14);
        cfknob->labelcolor(FL_FOREGROUND_COLOR);
        cfknob->maximum(127);
        cfknob->step(1);
        cfknob->callback((Fl_Callback*)cb_cfknob);
        cfknob->align(Fl_Align(FL_ALIGN_BOTTOM));
        cfknob->when(FL_WHEN_CHANGED);
        o->value(pars->Pcenterfreq);
      } // mwheel_slider_rev* cfknob
      { mwheel_slider_rev* o = octknob = new mwheel_slider_rev(547, 185, 90, 16);
        octknob->type(5);
        octknob->box(FL_THIN_DOWN_BOX);
        octknob->color(FL_BACKGROUND_COLOR);
        octknob->selection_color(FL_BACKGROUND_COLOR);
        octknob->labeltype(FL_NORMAL_LABEL);
        octknob->labelfont(0);
        octknob->labelsize(14);
        octknob->labelcolor(FL_FOREGROUND_COLOR);
        octknob->maximum(127);
        octknob->step(1);
        octknob->callback((Fl_Callback*)cb_octknob);
        octknob->align(Fl_Align(FL_ALIGN_BOTTOM));
        octknob->when(FL_WHEN_CHANGED);
        o->value(pars->Poctavesfreq);
      } // mwheel_slider_rev* octknob
      { WidgetPDial* o = wvknob = new WidgetPDial(600, 15, 25, 25, "Vw.Cl.");
        wvknob->tooltip("Vowel \"clearness\" (transition between vowels)");
        wvknob->box(FL_ROUND_UP_BOX);
        wvknob->color(FL_BACKGROUND_COLOR);
        wvknob->selection_color(FL_INACTIVE_COLOR);
        wvknob->labeltype(FL_NORMAL_LABEL);
        wvknob->labelfont(1);
        wvknob->labelsize(10);
        wvknob->labelcolor(FL_FOREGROUND_COLOR);
        wvknob->maximum(127);
        wvknob->step(1);
        wvknob->callback((Fl_Callback*)cb_wvknob);
        wvknob->align(Fl_Align(FL_ALIGN_TOP));
        wvknob->when(FL_WHEN_CHANGED);
        o->value(pars->Pvowelclearness);
        o->setValueType(VC_FormFilterClearness);
        o->setGraphicsType(VC_FormFilterClearness);
      } // WidgetPDial* wvknob
      { formClose = new Fl_Button(643, 170, 50, 25, "Close");
        formClose->box(FL_THIN_UP_BOX);
        formClose->callback((Fl_Callback*)cb_formClose);
      } // Fl_Button* formClose
      { formCopy = new Fl_Button(635, 25, 25, 15, "C");
        formCopy->box(FL_THIN_UP_BOX);
        formCopy->color((Fl_Color)179);
        formCopy->labelfont(1);
        formCopy->labelsize(11);
        formCopy->labelcolor(FL_BACKGROUND2_COLOR);
        formCopy->callback((Fl_Callback*)cb_formCopy);
      } // Fl_Button* formCopy
      { formPaste = new Fl_Button(665, 25, 25, 15, "P");
        formPaste->box(FL_THIN_UP_BOX);
        formPaste->color((Fl_Color)179);
        formPaste->labelfont(1);
        formPaste->labelsize(11);
        formPaste->labelcolor(FL_BACKGROUND2_COLOR);
        formPaste->callback((Fl_Callback*)cb_formPaste);
      } // Fl_Button* formPaste
      { formvowel = new Fl_Box(635, 7, 55, 15, "Vowel");
      } // Fl_Box* formvowel
      o->end();
    } // Fl_Group* o
    formantDW = o->w(); formantDH = o->h();
    o->size_range(formantDW, formantDH, 0, 0, 0, 0, 1);
    formantparswindow->end();
    formantparswindow->resizable(formantparswindow);
  } // Fl_Double_Window* formantparswindow
  // Formant graph
  {
        FormantFilterGraph* o = formantfiltergraph = new FormantFilterGraph(5, 5, 475, 195, *this, pars, &nvowel, &nformant);
        formantfiltergraph->box(FL_BORDER_BOX);
        formantparswindow->add(o);
  } // FormantFilterGraph* formantfiltergraph
  return formantparswindow;
}

void FilterUI::update_formant_window() {
  //
          formant_freq_dial->value(pars->Pvowels[nvowel].formants[nformant].freq);
          formant_q_dial->value(pars->Pvowels[nvowel].formants[nformant].q);
          formant_amp_dial->value(pars->Pvowels[nvowel].formants[nformant].amp);
          if (nformant < pars->Pnumformants)
              formantparsgroup->activate();
          else
              formantparsgroup->deactivate();
  
          if (nseqpos < pars->Psequencesize)
              vowel_counter->activate();
          else
              vowel_counter->deactivate();
  
          vowel_counter->value(pars->Psequence[nseqpos].nvowel);
}

void FilterUI::refresh() {
  //
          update_formant_window();
          formantfiltergraph->redraw();
          int categ = pars->Pcategory;
          int parstype = pars->Ptype;
          filtertype->value(categ);
          cfreqdial->value(pars->Pfreq);
          freqtrackoffset->value(pars->Pfreqtrackoffset);
          freqtrdial->setValueType(getFilterFreqTrackType(freqtrackoffset->value()));
          qdial->value(pars->Pq);
          freqtrdial->value(pars->Pfreqtrack);
          gaindial->value(pars->Pgain);
          stcounter->value(fetchData(0, FILTERINSERT::control::stages, npart, kititem, engine, TOPLEVEL::insert::filterGroup) + 1);
  
          qdial->activate();
          if (categ != 1)
          {
              if (categ == 0)
              {
                  analogfiltertypechoice->value(parstype);
                  analogfiltertypechoice->show();
                  svfiltertypechoice->hide();
                  if (parstype < 2)
                      qdial->deactivate();
              }
              else
              {
                  svfiltertypechoice->value(parstype);
                  svfiltertypechoice->show();
                  analogfiltertypechoice->hide();
              }
              editbutton->hide();
              formantparswindow->hide();
              cfreqdial->label("C.freq");
          }
          else
          {
              analogfiltertypechoice->hide();
              svfiltertypechoice->hide();
              editbutton->show();
              cfreqdial->label("BS.pos");
          }
          filterparamswindow->redraw();
}

void FilterUI::filterRtext(float dScale) {
  //
              int size = int(dScale * 10);
  
              filterparamslabel->labelsize(size);
  
              cfreqdial->labelsize(size);
              qdial->labelsize(size);
              freqtrdial->labelsize(size);
              vsnsadial->labelsize(size);
              vsnsdial->labelsize(size);
              gaindial->labelsize(size);
  
              filtertype->labelsize(size);
                  filtertype->textsize(size);
  
              stcounter->labelsize(size);
              stcounter->textsize(size);
  
              analogfiltertypechoice->labelsize(size);
                  analogfiltertypechoice->textsize(size);
  
              svfiltertypechoice->labelsize(size);
                  svfiltertypechoice->textsize(size);
  
              editbutton->labelsize(size);
              filtC->labelsize(size);
              filtP->labelsize(size);
              freqtrackoffset->labelsize(size);
              freqtracknormal->labelsize(size);
              freqtrackchecked->labelsize(size);
}

void FilterUI::formantRtext() {
  //
      /*
       * This is very different from other windows because it is called
       * via the draw method, not the usual chain.
      */
  
      if (lastformantX == formantparswindow->x() && lastformantY == formantparswindow->y() &&lastformantW == formantparswindow->w())
          return;
      lastformantX = formantparswindow->x();
      lastformantY = formantparswindow->y();
      lastformantW = formantparswindow->w();
  
      //std::cout << "formant seen" << std::endl;
      float dScale = formantparswindow->w() / float(formantDW);
  
      int size = int(10 * dScale);
      int size11 = int(11 * dScale);
      int size12 = int(12 * dScale);
      int size14 = int(14 * dScale);
  
      formantnumber->labelsize(size);
          formantnumber->textsize(size);
      vowelnumber->labelsize(size);
          vowelnumber->textsize(size11);
  
      formant_freq_dial->labelsize(size);
      formant_q_dial->labelsize(size);
      formant_amp_dial->labelsize(size);
  
      seqsize->labelsize(size);
          seqsize->textsize(size11);
      seqpos->labelsize(size);
          seqpos->textsize(size);
      vowel_counter->labelsize(size);
          vowel_counter->textsize(size);
      neginput->labelsize(size);
      strchdial->labelsize(size);
      formantcount->labelsize(size);
          formantcount->textsize(size12);
      frsldial->labelsize(size);
      centerfreqvo->labelsize(size12);
          centerfreqvo->textsize(size11);
      octavesfreqvo->labelsize(size12);
          octavesfreqvo->textsize(size11);
      wvknob->labelsize(size);
  
      formClose->labelsize(size14);
      formvowel->labelsize(size14);
      formCopy->labelsize(size11);
      formPaste->labelsize(size11);
}

void FilterUI::send_data(int action, int control, float value, int type, int parameter , int offset ) {
  //
          type |= TOPLEVEL::type::Write;
          collect_data(synth, value, action, type, control, npart, kititem, engine, TOPLEVEL::insert::filterGroup, parameter, offset);
}

float FilterUI::fetchData(float value, int control, int part, int kititem , int engine , int insert , int parameter , int offset , int miscmsg , int request ) {
  //
          return collect_readData(synth, value, control, part, kititem, engine, insert, parameter, offset, miscmsg, request);
}

void FilterUI::returns_update(CommandBlock *getData) {
  //
      float value = getData->data.value;
      unsigned char control = getData->data.control;
      unsigned char part = getData->data.part;
      unsigned char kititem = getData->data.kit;
      unsigned char eng = getData->data.engine;
      unsigned char param =  getData->data.parameter;
      unsigned char offset =  getData->data.offset;
  
      bool isCurrent =  (param == nformant && offset == nvowel);
  
      int value_int = lrint(value);
  
      bool fromUs = ((getData->data.source & TOPLEVEL::action::noAction) == TOPLEVEL::action::fromGUI);
  
      if (part != npart || (kititem != (EFFECT::type::dynFilter) && eng != engine))
          return;
      if (kititem == (EFFECT::type::dynFilter))
      {
          //cout << "Dyn filter seen part " << int(part)<< endl;
          if (part == TOPLEVEL::section::systemEffects)
              synth->getGuiMaster()->syseffectui->UpdatePresetColour(1, EFFECT::type::dynFilter - EFFECT::type::none);
          else if (part == TOPLEVEL::section::insertEffects)
              synth->getGuiMaster()->inseffectui->UpdatePresetColour(1, EFFECT::type::dynFilter - EFFECT::type::none);
          else
             synth->getGuiMaster()->partui->inseffectui->UpdatePresetColour(1, EFFECT::type::dynFilter - EFFECT::type::none); // normal part effect
      }
  
      qdial->activate();
      switch(control)
      {
          case FILTERINSERT::control::centerFrequency:
              cfreqdial->value(value);
              break;
  
          case FILTERINSERT::control::Q:
              qdial->value(value);
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::frequencyTracking:
              freqtrdial->value(value_int);
              break;
  
          case FILTERINSERT::control::velocitySensitivity:
              vsnsadial->value(value);
              if (velsnsamp != NULL)
                  *velsnsamp = value_int;
              break;
  
          case FILTERINSERT::control::velocityCurve:
              vsnsdial->value(value);
              if (velsns != NULL)
                  *velsns = value_int;
              break;
  
          case FILTERINSERT::control::gain:
              gaindial->value(value);
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::stages:
              if (!fromUs)
                  stcounter->value(value_int + 1);
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::baseType:
              filtertype->value(value_int);
              cfreqdial->setValueType(getFilterFreqType(value_int));
              updateVCforQ();
              refresh();
              break;
  
          case FILTERINSERT::control::analogType:
              analogfiltertypechoice->value(value_int);
              if (value_int < 2)
                  qdial->deactivate();
              updateVCforQ();
              break;
  
          case FILTERINSERT::control::stateVariableType:
              svfiltertypechoice->value(value_int);
              break;
  
          case FILTERINSERT::control::frequencyTrackingRange:
              freqtrackoffset->value(value_int);
              freqtrdial->setValueType(getFilterFreqTrackType(value_int));
              if (value_int)
              {
                  freqtracknormal->hide();
                  freqtrackchecked->show();
              }
              else
              {
                  freqtracknormal->show();
                  freqtrackchecked->hide();
              }
              break;
  
          case FILTERINSERT::control::formantSlowness:
              frsldial->value(value);
              break;
  
          case FILTERINSERT::control::formantClearness:
              wvknob->value(value);
              break;
  
          case FILTERINSERT::control::formantFrequency:
              if (isCurrent)
              {
                  formant_freq_dial->value(value);
                  formantfiltergraph->redraw();
              }
              break;
  
          case FILTERINSERT::control::formantQ:
              if (isCurrent)
              {
                  formant_q_dial->value(value);
                  formantfiltergraph->redraw();
              }
              break;
  
          case FILTERINSERT::control::formantAmplitude:
              if (isCurrent)
              {
                  formant_amp_dial->value(value);
                  formantfiltergraph->redraw();
              }
              break;
  
          case FILTERINSERT::control::formantStretch:
              strchdial->value(value);
              break;
  
          case FILTERINSERT::control::formantCenter:
              cfknob->value(value);
              if (!fromUs)
                  centerfreqvo->do_callback();
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::formantOctave:
              octknob->value(value);
              if (!fromUs)
                  octavesfreqvo->do_callback();
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::numberOfFormants:
              formantcount->value(value_int);
              update_formant_window();
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::vowelNumber:
              nvowel = value_int;
              update_formant_window();
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::formantNumber:
              nformant = value_int;
              update_formant_window();
              formantfiltergraph->redraw();
              break;
  
          case FILTERINSERT::control::sequenceSize:
              seqsize->value(value_int);
              update_formant_window();
              break;
  
          case FILTERINSERT::control::sequencePosition:
              update_formant_window();
              break;
  
          case FILTERINSERT::control::vowelPositionInSequence:
              vowel_counter->value(value_int);
              break;
  
          case FILTERINSERT::control::negateInput:
              neginput->value(value != 0);
              break;
      }
}

void FilterUI::init(FilterParams *filterpars_,unsigned char *velsnsamp_,unsigned char *velsns_, int npart_, int kititem_, int engine_) {
  //
      pars=filterpars_;
      synth = pars->getSynthEngine();
      velsnsamp = velsnsamp_;
      velsns = velsns_;
      npart = npart_;
      kititem = kititem_;
      engine = engine_;
      lastformantX = 0;
      lastformantY = 0;
      lastformantW = 0;
      formantSeen = false;
      make_window();
      end();
      make_formant_window();
      filterui->resize(this->x(), this->y(), this->w(), this->h());
  
      if (velsnsamp == NULL)
      {
          vsnsadial->deactivate();
          vsnsadial->value(127);
      }
      else
          vsnsadial->value(*velsnsamp);
  
      if (velsns == NULL)
      {
          vsnsdial->deactivate();
          vsnsdial->value(127);
      }
      else
          vsnsdial->value(*velsns);
      cfreqdial->setValueType(getFilterFreqType(pars->Pcategory));
      updateVCforQ();
  
      analogfiltertypechoice->value(0);
      svfiltertypechoice->value(0);
      stcounter->value(fetchData(0, FILTERINSERT::control::stages, npart, kititem, engine, TOPLEVEL::insert::filterGroup) + 1);
      formantparswindow->label(this->label());
      refresh();
}

void FilterUI::updateVCforQ() {
  //
      switch (filtertype->value())
      {
          case 0:
              if (analogfiltertypechoice->value()<2)
                  qdial->setValueType(VC_FilterQAnalogUnused);
              else
                  qdial->setValueType(VC_FilterQ);
              break;
          case 1:
          case 2:
              qdial->setValueType(VC_FilterQ);
      }
}
