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

#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-2025 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/TextMsgBuffer.h"

    namespace { // Implementation details...
        TextMsgBuffer& textMsgBuffer = TextMsgBuffer::instance();
    }
#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(graph_back);
          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(formant_marker);
          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(formant_ghost_marker);
              draw_freq_line(pars->getformantfreq(pars->Pvowels[*nvowel].formants[hoverFormant].freq));
          }

          // draw the data
          fl_color(formant_graph_line);

          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);
          ;
}

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
        /*
         * right mouse button is now universally used for MIDI-learn
         * so we use the shift key instead.
         *
         * qMode = Fl::event_button() == FL_RIGHT_MOUSE
         *    || (Fl::event_button() == FL_MIDDLE_MOUSE && qMode);
         */

          qMode = Fl::event_key(FL_Shift_L)
              || Fl::event_key(FL_Shift_R);

        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:
    {
        /*
         * These two had stopped working due to some unknown change
         * elsewhere, hence the more convulated code.
         * Original has been kept but commented out.
         */
        float tmp;
        int offset = Fl::event_dy() * (Fl::event_ctrl() ? 1 : 4);
        if (Fl::event_shift())
        {
            tmp = (parent.cfknob->value() + offset) / 5;
            if (tmp > 127)
                tmp = 127;
            else if (tmp < 0)
                tmp = 0;
            parent.send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantCenter, tmp, TOPLEVEL::type::Write);
            //delegate(parent.cfknob, limit(pars->Pcenterfreq + offset, 0, 127));
        }
        else
        {
            tmp = (parent.octknob->value() + offset) / 5;
            if (tmp > 127)
                tmp = 127;
            else if (tmp < 0)
                tmp = 0;
            parent.send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantOctave, tmp, TOPLEVEL::type::Write);
            //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 + 1)
          {
              w->value(value + 1);
              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(TOPLEVEL::action::forceUpdate, 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;
      formantparswindow->copy_label(textMsgBuffer.fetch(collect_readData(synth, textMsgBuffer.push("Formant Editor"), npart, TOPLEVEL::windowTitle, kititem, engine)).c_str());
      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()->Ucopy(npart, kititem, engine, TOPLEVEL::insert::filterGroup);
              ;
}
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()->Upaste(npart, kititem, engine, TOPLEVEL::insert::filterGroup);
              ;
}
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(ScaleTrackedWindow*, void*) {
  formClose->do_callback();
}
void FilterUI::cb_formantparswindow(ScaleTrackedWindow* 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()) - 1;
            if (nformant >= nFoCount)
            {
                nformant =  nFoCount - 1;
                o->value(nformant + 1);
            }
            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() - 1);

            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::vowelNumber, nvowel, 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*) {
  //
              float val = findDynDef(0);//formFreqDef;
              if (Fl::event_button() == 3)
              {
                  o->value(val);
              }
              o->selection_color(setKnob(o->value(),val)); // has pseudo default
              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*) {
  //
              float val = o->value();
              if (Fl::event_button() == 3)
              {
                  val = FILTDEF::formQ.def;
                  o->value(val);
              }
              o->selection_color(setKnob(val,FILTDEF::formQ.def));
              send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantQ, val, 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*) {
  //
              float val = findDynDef(2);
              if (Fl::event_button() == 3)
                  o->value(val);
              o->selection_color(setKnob(o->value(),val));
              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*) {
  //
            nseqsize = o->value();
            if (nseqpos > nseqsize)
            {
                nseqpos = nseqsize;
                seqpos->value(nseqpos);
            }


            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::sequenceSize, nseqsize, 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() - 1);
            if (nseqpos >= nseqsize)
            {
                nseqpos = nseqsize - 1;
                o->value(nseqpos + 1);
            }

            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::sequencePosition, nseqpos, 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*) {
  //
            nVoCount = o->value() - 1;

            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::vowelPositionInSequence, nVoCount, 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*) {
  //
            float val = o->value();
            if (Fl::event_button() == 3)
            {
                val = FILTDEF::formStretch.def;
                o->value(val);
            }

            o->selection_color(setKnob(val,FILTDEF::formStretch.def));
            send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantStretch,val, 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*) {
  //
          nFoCount = o->value();

          if (nformant >= nFoCount)
            {
                nformant =  nFoCount -1;
                formantnumber->value(nformant + 1);
            }

          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::numberOfFormants,nFoCount, 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*) {
  //
          float val = o->value();
          if (Fl::event_button() == 3)
          {
              val = FILTDEF::formSpeed.def;
              o->value(val);
          }

          o->selection_color(setKnob(val,FILTDEF::formSpeed.def));
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantSlowness, val, 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(lrintf(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(FILTDEF::formCentre.def*5);
          o->selection_color(setSlider(o->value(),FILTDEF::formCentre.def*5));
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantCenter, o->value()/5, 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(FILTDEF::formOctave.def*5);
          o->selection_color(setSlider(o->value(),FILTDEF::formOctave.def*5));
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::formantOctave, o->value()/5, 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*) {
  //
          float val = findDynClearDef();
          if (Fl::event_button() == 3)
          {
              o->value(val);
          }

          o->selection_color(setKnob(o->value(),val));
          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()->Ucopy(npart, kititem, engine, TOPLEVEL::insert::filterGroup,0, nvowel);
                // dummy parameter always stores all possible formants
                ;
}
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()->Upaste(npart, kititem, engine, TOPLEVEL::insert::filterGroup,0, nvowel);
                // dummy parameter always stores all possible formants
                ;
}
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;
          nseqsize = 3;
          nVoCount = 0;
          nFoCount = 0;
          formFreqDef = -1;
}

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_LIGHT1);
    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_CYAN);
      filterparamswindow->labelfont(1);
      filterparamswindow->labelsize(10);
      filterparamswindow->labelcolor((Fl_Color)64);
      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->selection_color((Fl_Color)64);
        analogfiltertypechoice->labelsize(10);
        analogfiltertypechoice->labelcolor((Fl_Color)64);
        analogfiltertypechoice->textfont(1);
        analogfiltertypechoice->textsize(10);
        analogfiltertypechoice->textcolor((Fl_Color)64);
        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->selection_color((Fl_Color)64);
        svfiltertypechoice->labelsize(10);
        svfiltertypechoice->labelcolor((Fl_Color)64);
        svfiltertypechoice->textfont(1);
        svfiltertypechoice->textsize(10);
        svfiltertypechoice->textcolor((Fl_Color)64);
        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->selection_color((Fl_Color)64);
        filtertype->labelsize(10);
        filtertype->labelcolor((Fl_Color)64);
        filtertype->textfont(1);
        filtertype->textsize(10);
        filtertype->textcolor((Fl_Color)64);
        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_Color)64);
        cfreqdial->maximum(127);
        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
      { 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_Color)64);
        qdial->maximum(127);
        qdial->callback((Fl_Callback*)cb_qdial);
        qdial->align(Fl_Align(FL_ALIGN_BOTTOM));
        qdial->when(FL_WHEN_CHANGED);
        qdial->deactivate();
      } // 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_Color)64);
        freqtrdial->maximum(127);
        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_Color)64);
        vsnsadial->maximum(127);
        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_Color)64);
        vsnsdial->maximum(127);
        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_Color)64);
        gaindial->maximum(127);
        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(73, 10, 41, 15, "St.");
        stcounter->tooltip("Filter stages (in order to increase dB/oct. value and the order of the filter"
")");
        stcounter->type(1);
        stcounter->selection_color((Fl_Color)64);
        stcounter->labelsize(10);
        stcounter->labelcolor((Fl_Color)64);
        stcounter->minimum(1);
        stcounter->maximum(5);
        stcounter->step(1);
        stcounter->value(1);
        stcounter->textfont(1);
        stcounter->textsize(10);
        stcounter->textcolor((Fl_Color)64);
        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);
      filterparamslabel->labelcolor((Fl_Color)64);
    } // Fl_Text_Display* filterparamslabel
    { editbutton = new Fl_Button(5, 40, 52, 26, "Edit");
      editbutton->box(FL_GTK_THIN_UP_BOX);
      editbutton->selection_color((Fl_Color)221);
      editbutton->labelfont(1);
      editbutton->labelsize(11);
      editbutton->labelcolor((Fl_Color)64);
      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_Color)197);
      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_Color)197);
      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_Color)64);
      freqtrackoffset->labeltype(FL_NORMAL_LABEL);
      freqtrackoffset->labelfont(0);
      freqtrackoffset->labelsize(14);
      freqtrackoffset->labelcolor((Fl_Color)64);
      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->selection_color((Fl_Color)64);
      freqtracknormal->labelsize(10);
      freqtracknormal->labelcolor((Fl_Color)64);
      freqtracknormal->textsize(10);
      freqtracknormal->textcolor((Fl_Color)64);
    } // Fl_Text_Display* freqtracknormal
    { freqtrackchecked = new Fl_Text_Display(242, 24, 44, 4, "0/+");
      freqtrackchecked->box(FL_NO_BOX);
      freqtrackchecked->selection_color((Fl_Color)64);
      freqtrackchecked->labelsize(10);
      freqtrackchecked->labelcolor((Fl_Color)64);
      freqtrackchecked->textsize(10);
      freqtrackchecked->textcolor((Fl_Color)64);
      freqtrackchecked->hide();
    } // Fl_Text_Display* freqtrackchecked
    filterui->end();
  } // Fl_Group* filterui
  return filterui;
}

ScaleTrackedWindow* FilterUI::make_formant_window() {
  { ScaleTrackedWindow* o = formantparswindow = new ScaleTrackedWindow(700, 205, "Formant Filter Parameters");
    formantparswindow->box(FL_FLAT_BOX);
    formantparswindow->color(FL_BACKGROUND_COLOR);
    formantparswindow->selection_color(FL_BACKGROUND_COLOR);
    formantparswindow->labeltype(FL_NO_LABEL);
    formantparswindow->labelfont(1);
    formantparswindow->labelsize(12);
    formantparswindow->labelcolor(FL_FOREGROUND_COLOR);
    formantparswindow->callback((Fl_Callback*)cb_formantparswindow, (void*)(this));
    formantparswindow->align(Fl_Align(FL_ALIGN_TOP));
    formantparswindow->when(FL_WHEN_RELEASE);
    { 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_FRAME);
        { Fl_Counter* o = formantnumber = new Fl_Counter(545, 80, 40, 15, "Formant ");
          formantnumber->type(1);
          formantnumber->selection_color((Fl_Color)64);
          formantnumber->labelfont(1);
          formantnumber->labelsize(10);
          formantnumber->labelcolor((Fl_Color)64);
          formantnumber->minimum(1);
          formantnumber->maximum(127);
          formantnumber->step(1);
          formantnumber->value(1);
          formantnumber->textsize(10);
          formantnumber->textcolor((Fl_Color)64);
          formantnumber->callback((Fl_Callback*)cb_formantnumber);
          formantnumber->align(Fl_Align(FL_ALIGN_LEFT));
          o->bounds(1,FF_MAX_FORMANTS);
          o->value(nformant + 1);
        } // Fl_Counter* formantnumber
        { Fl_Counter* o = vowelnumber = new Fl_Counter(545, 55, 40, 20);
          vowelnumber->type(1);
          vowelnumber->selection_color((Fl_Color)64);
          vowelnumber->labelfont(1);
          vowelnumber->labelsize(10);
          vowelnumber->labelcolor((Fl_Color)64);
          vowelnumber->minimum(1);
          vowelnumber->maximum(127);
          vowelnumber->step(1);
          vowelnumber->value(1);
          vowelnumber->textfont(1);
          vowelnumber->textsize(11);
          vowelnumber->textcolor((Fl_Color)64);
          vowelnumber->callback((Fl_Callback*)cb_vowelnumber);
          vowelnumber->align(Fl_Align(FL_ALIGN_LEFT));
          o->bounds(1,FF_MAX_VOWELS);
          o->value(nvowel + 1);
        } // Fl_Counter* vowelnumber
        { vowelpatch = new Fl_Box(487, 56, 56, 18, "Vowel no.");
          vowelpatch->box(FL_FLAT_BOX);
          vowelpatch->labelfont(1);
          vowelpatch->labelsize(10);
          vowelpatch->labelcolor((Fl_Color)64);
        } // Fl_Box* vowelpatch
        { 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_Color)64);
            formant_freq_dial->maximum(127);
            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_Color)64);
            formant_q_dial->maximum(127);
            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_Color)64);
            formant_amp_dial->maximum(127);
            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, 104, 113);
        o->box(FL_THIN_UP_BOX);
        { Fl_Counter* o = seqsize = new Fl_Counter(614, 62, 54, 18, "Seq.Size");
          seqsize->type(1);
          seqsize->selection_color((Fl_Color)64);
          seqsize->labelfont(1);
          seqsize->labelsize(10);
          seqsize->labelcolor((Fl_Color)64);
          seqsize->minimum(1);
          seqsize->maximum(127);
          seqsize->step(1);
          seqsize->value(1);
          seqsize->textfont(1);
          seqsize->textsize(11);
          seqsize->textcolor((Fl_Color)64);
          seqsize->callback((Fl_Callback*)cb_seqsize);
          seqsize->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          o->bounds(1,FF_MAX_SEQUENCE);
          o->value(nseqsize);
        } // Fl_Counter* seqsize
        { Fl_Counter* o = seqpos = new Fl_Counter(596, 98, 40, 15, "S.Pos.");
          seqpos->tooltip("Current position in the sequence");
          seqpos->type(1);
          seqpos->selection_color((Fl_Color)64);
          seqpos->labelfont(1);
          seqpos->labelsize(10);
          seqpos->labelcolor((Fl_Color)64);
          seqpos->minimum(1);
          seqpos->maximum(127);
          seqpos->step(1);
          seqpos->value(1);
          seqpos->textsize(10);
          seqpos->textcolor((Fl_Color)64);
          seqpos->callback((Fl_Callback*)cb_seqpos);
          seqpos->align(Fl_Align(FL_ALIGN_TOP_RIGHT));
          o->bounds(1,FF_MAX_SEQUENCE);
          o->value(nseqpos + 1);
        } // Fl_Counter* seqpos
        { Fl_Counter* o = vowel_counter = new Fl_Counter(648, 98, 40, 15, "Vowel");
          vowel_counter->tooltip("Vowel number at the sequence position");
          vowel_counter->type(1);
          vowel_counter->selection_color((Fl_Color)64);
          vowel_counter->labelsize(10);
          vowel_counter->labelcolor((Fl_Color)64);
          vowel_counter->minimum(1);
          vowel_counter->maximum(127);
          vowel_counter->step(1);
          vowel_counter->value(1);
          vowel_counter->textsize(10);
          vowel_counter->textcolor((Fl_Color)64);
          vowel_counter->callback((Fl_Callback*)cb_vowel_counter);
          vowel_counter->align(Fl_Align(FL_ALIGN_TOP));
          o->bounds(1,FF_MAX_VOWELS);
        } // Fl_Counter* vowel_counter
        { Fl_Check_Button2* o = neginput = new Fl_Check_Button2(628, 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_Color)64);
          neginput->labeltype(FL_NORMAL_LABEL);
          neginput->labelfont(0);
          neginput->labelsize(10);
          neginput->labelcolor((Fl_Color)64);
          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, "Stretch");
          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_Color)64);
          strchdial->maximum(127);
          strchdial->callback((Fl_Callback*)cb_strchdial);
          strchdial->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          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, 19, 65, 20, "Formants");
        formantcount->type(1);
        formantcount->selection_color((Fl_Color)64);
        formantcount->labelsize(12);
        formantcount->labelcolor((Fl_Color)64);
        formantcount->minimum(1);
        formantcount->maximum(127);
        formantcount->step(1);
        formantcount->value(1);
        formantcount->textsize(12);
        formantcount->textcolor((Fl_Color)64);
        formantcount->callback((Fl_Callback*)cb_formantcount);
        formantcount->align(Fl_Align(FL_ALIGN_TOP));
        o->bounds(1,FF_MAX_FORMANTS);
      } // 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_Color)64);
        frsldial->maximum(127);
        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->labelcolor((Fl_Color)64);
        centerfreqvo->minimum(1);
        centerfreqvo->maximum(127);
        centerfreqvo->step(0.1);
        centerfreqvo->value(64);
        centerfreqvo->textfont(1);
        centerfreqvo->textsize(11);
        centerfreqvo->textcolor((Fl_Color)64);
        centerfreqvo->callback((Fl_Callback*)cb_centerfreqvo);
        centerfreqvo->when(FL_WHEN_CHANGED | FL_WHEN_NOT_CHANGED);
        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->labelcolor((Fl_Color)64);
        octavesfreqvo->minimum(1);
        octavesfreqvo->maximum(127);
        octavesfreqvo->step(1);
        octavesfreqvo->value(5);
        octavesfreqvo->textfont(1);
        octavesfreqvo->textsize(11);
        octavesfreqvo->textcolor((Fl_Color)64);
        octavesfreqvo->callback((Fl_Callback*)cb_octavesfreqvo);
        octavesfreqvo->when(FL_WHEN_CHANGED | FL_WHEN_NOT_CHANGED);
        o->step(1, 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_Color)64);
        cfknob->maximum(635);
        cfknob->step(1);
        cfknob->value(1);
        cfknob->callback((Fl_Callback*)cb_cfknob);
        cfknob->align(Fl_Align(FL_ALIGN_BOTTOM));
        cfknob->when(FL_WHEN_CHANGED);
        o->value(pars->Pcenterfreq*5);
        o->selection_color(setSlider(pars->Pcenterfreq,FILTDEF::formCentre.def));
      } // 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_Color)64);
        octknob->maximum(635);
        octknob->step(1);
        octknob->value(5);
        octknob->callback((Fl_Callback*)cb_octknob);
        octknob->align(Fl_Align(FL_ALIGN_BOTTOM));
        octknob->when(FL_WHEN_CHANGED);
        o->value(pars->Poctavesfreq*5);
        o->selection_color(setSlider(pars->Poctavesfreq,FILTDEF::formOctave.def));
      } // 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_Color)64);
        wvknob->maximum(127);
        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->color((Fl_Color)196);
        formClose->labelcolor((Fl_Color)64);
        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_Color)197);
        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_Color)197);
        formPaste->callback((Fl_Callback*)cb_formPaste);
      } // Fl_Button* formPaste
      { formvowel = new Fl_Box(635, 8, 55, 15, "Vowel");
        formvowel->labelcolor((Fl_Color)64);
      } // Fl_Box* formvowel
      { Fl_Box* o = new Fl_Box(630, 4, 64, 40);
        o->box(FL_EMBOSSED_FRAME);
      } // Fl_Box* o
      o->end();
    } // Fl_Group* o
    formantparswindow->resizable(formantparswindow);
    formantDW = o->w(); formantDH = o->h();
    o->size_range(formantDW, formantDH, 0, 0, 0, 0, 1);
    formantparswindow->end();
  } // ScaleTrackedWindow* 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() {
  //
          formFreqDef = pars->Pvowels[nvowel].formants[nformant].firstF;
          formant_freq_dial->value(pars->Pvowels[nvowel].formants[nformant].freq);
          formant_freq_dial->selection_color(setKnob(formant_freq_dial->value(),findDynDef(0)));
          formant_q_dial->value(pars->Pvowels[nvowel].formants[nformant].q);
          formant_q_dial->selection_color(setKnob( formant_q_dial->value(),FILTDEF::formQ.def));
          formant_amp_dial->value(pars->Pvowels[nvowel].formants[nformant].amp);
          formant_amp_dial->selection_color(setKnob( formant_amp_dial->value(),findDynDef(2)));
          nseqsize = pars->Psequencesize;
          seqsize->value(nseqsize);

          nFoCount = fetchData(0, FILTERINSERT::control::numberOfFormants, npart, kititem, engine, TOPLEVEL::insert::filterGroup);
          formantcount->value(nFoCount);
          nVoCount = fetchData(0, FILTERINSERT::control::vowelPositionInSequence, npart, kititem, engine, TOPLEVEL::insert::filterGroup, nseqpos);
          vowel_counter->value(nVoCount + 1);
}

void FilterUI::check_vowel() {
  //
          bool vowelseen = false;
          for (int i = 0; i < nseqsize; ++i)
          {
              if ((nvowel) == fetchData(0, FILTERINSERT::control::vowelPositionInSequence, npart, kititem, engine, TOPLEVEL::insert::filterGroup, i))
                  vowelseen = true;
          }
          if (vowelseen)
              vowelpatch->color(FL_BACKGROUND_COLOR);
          else
               vowelpatch->color(warning_background);
          vowelpatch->redraw();
}

void FilterUI::refresh() {
  //
          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);

          qdial->activate();
          switch (categ)
          {
              case 0:
              {
                  analogfiltertypechoice->value(parstype);
                  analogfiltertypechoice->show();
                  svfiltertypechoice->hide();
                  editbutton->hide();
                  formantparswindow->hide();
                  cfreqdial->label("C.freq");
                  if (parstype < 2)
                      qdial->deactivate();
                  break;
              }
              case 1:
              {
                  analogfiltertypechoice->hide();
                  svfiltertypechoice->hide();
                  editbutton->show();
                  update_formant_window();
                  check_vowel();
                  formantfiltergraph->redraw();
                  cfreqdial->label("BS.pos");
                  break;
              }
              case 2:
              {

                  svfiltertypechoice->value(parstype);
                  svfiltertypechoice->show();
                  analogfiltertypechoice->hide();
                  editbutton->hide();
                  formantparswindow->hide();
                  stcounter->value(fetchData(0, FILTERINSERT::control::stages, npart, kititem, engine, TOPLEVEL::insert::filterGroup) + 1);
                  cfreqdial->label("C.freq");
                  break;
              }
          }

          if (kititem == EFFECT::type::dynFilter)
          {
              dynFilt = true;
              dynPreset = fetchData(0, EFFECT::control::preset, npart, kititem, engine);
              switch (dynPreset)
              {
                  case 0:
                  {
                      cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::dynFreq0.def));
                      qdial->selection_color(setKnob(qdial->value(),FILTDEF::dynQval0.def));
                      break;
                  }
                  case 1:
                  {
                      cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::dynFreq1.def));
                      qdial->selection_color(setKnob(qdial->value(),FILTDEF::dynQval1.def));
                      break;
                  }
                  case 2:
                  {
                      cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::dynFreq2.def));
                      qdial->selection_color(setKnob(qdial->value(),FILTDEF::dynQval2.def));
                      break;
                  }
                  case 3:
                  {
                      cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::dynFreq3.def));
                      qdial->selection_color(setKnob(qdial->value(),FILTDEF::dynQval3.def));
                      break;
                  }
                  case 4:
                  {
                      cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::dynFreq4.def));
                      qdial->selection_color(setKnob(qdial->value(),FILTDEF::dynQval4.def));
                      break;
                  }
              }
          }
          else
          {
              if (engine == PART::engine::addSynth ||engine == PART::engine::padSynth )
                  cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::addFreq.def));
              else if (engine == PART::engine::subSynth)
                  cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::subFreq.def));

              if (engine >= PART::engine::addVoice1)
              {
                  cfreqdial->selection_color(setKnob(cfreqdial->value(),FILTDEF::voiceFreq.def));
                  qdial->selection_color(setKnob(qdial->value(),FILTDEF::voiceQval.def));
              }
              else
                  qdial->selection_color(setKnob(qdial->value(),FILTDEF::qVal.def));
          }

          if (categ == 0)
          {
              if (parstype < 2)
                  qdial->deactivate();
              else
                  qdial->activate();
          }
          updateVCforQ();

          freqtrdial->selection_color(setKnob(freqtrdial->value(),FILTDEF::freqTrack.def));

          if (engine >= PART::engine::addVoice1 && engine < PART::addVoiceModEnd)
              vsnsadial->selection_color(setKnob(vsnsadial->value(),FILTDEF::voiceVelSense.def));
          else
              vsnsadial->selection_color(setKnob(vsnsadial->value(),FILTDEF::velSense.def));

          vsnsdial->selection_color(setKnob(vsnsdial->value(),FILTDEF::velFuncSense.def));

          gaindial->selection_color(setKnob(gaindial->value(),FILTDEF::gain.def));

          frsldial->selection_color(setKnob(frsldial->value(),FILTDEF::formSpeed.def));

          wvknob->selection_color(setKnob(wvknob->value(),findDynClearDef()));

          formant_freq_dial->selection_color(setKnob(formant_freq_dial->value(),findDynDef(0)));

          formant_q_dial->selection_color(setKnob(formant_q_dial->value(),FILTDEF::formQ.def));

          formant_amp_dial->selection_color(setKnob(formant_amp_dial->value(),findDynDef(2)));

          strchdial->selection_color(setKnob(strchdial->value(),FILTDEF::formStretch.def));

          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::theme() {
  //
          if(formantparswindow)
          {
              if(formantparswindow->visible())
              {
                  lastformantX = 0;
                  formantRtext();
                  formantparswindow->redraw();
              }
          }
          ;
}

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);
      vowelpatch->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(size12);
          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_writeData(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 = lrintf(value);

      bool fromUs = ((getData->data.source & TOPLEVEL::action::noAction) == TOPLEVEL::action::fromGUI);

      dynFilt = (kititem == EFFECT::type::dynFilter);

      if (part != npart || (!dynFilt && eng != engine))
          return;
      if (dynFilt)
      {
          //std::cout << "is dyn " << value << std::endl;
          dynPreset = fetchData(0, EFFECT::control::preset, npart, kititem, engine);

          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
      }

      bool isAdd = (eng == PART::engine::addSynth);
      bool isVoice = (eng >= PART::engine::addVoice1);
      bool isSub = (eng == PART::engine::subSynth);
      bool isPad = (eng == PART::engine::padSynth);

      switch(control)
      {
          case FILTERINSERT::control::centerFrequency:
          {
              cfreqdial->value(value);
              if (dynFilt)
              {
                  switch (dynPreset)
                  {
                      case 0:
                          cfreqdial->selection_color(setKnob(value,FILTDEF::dynFreq0.def));
                          break;
                      case 1:
                          cfreqdial->selection_color(setKnob(value,FILTDEF::dynFreq1.def));
                          break;
                      case 2:
                          cfreqdial->selection_color(setKnob(value,FILTDEF::dynFreq2.def));
                          break;
                      case 3:
                          cfreqdial->selection_color(setKnob(value,FILTDEF::dynFreq3.def));
                          break;
                      case 4:
                          cfreqdial->selection_color(setKnob(value,FILTDEF::dynFreq4.def));
                          break;
                  }
                  formantfiltergraph->redraw();
              }
              else if(isAdd)
                  cfreqdial->selection_color(setKnob(value,FILTDEF::addFreq.def));
              else if(isVoice)
                  cfreqdial->selection_color(setKnob(value,FILTDEF::voiceFreq.def));
              else if (isSub)
                  cfreqdial->selection_color(setKnob(value,FILTDEF::subFreq.def));
              else if(isPad)
                  cfreqdial->selection_color(setKnob(value,FILTDEF::padFreq.def));
              break;
          }

          case FILTERINSERT::control::Q:
          {
              qdial->value(value);

              if (dynFilt)
              {
                  switch (dynPreset)
                  {
                      case 0:
                          qdial->selection_color(setKnob(value,FILTDEF::dynQval0.def));
                          break;
                      case 1:
                          qdial->selection_color(setKnob(value,FILTDEF::dynQval1.def));
                          break;
                      case 2:
                          qdial->selection_color(setKnob(value,FILTDEF::dynQval2.def));
                          break;
                      case 3:
                          qdial->selection_color(setKnob(value,FILTDEF::dynQval3.def));
                          break;
                      case 4:
                          qdial->selection_color(setKnob(value,FILTDEF::dynQval4.def));
                          break;
                  }
                  formantfiltergraph->redraw();
              }
              else if (isVoice)
                  qdial->selection_color(setKnob(value,FILTDEF::voiceQval.def));
              else
                  qdial->selection_color(setKnob(value,FILTDEF::qVal.def));
              if (filtertype->value() == 1)
                  formantfiltergraph->redraw();
              break;
          }

          case FILTERINSERT::control::frequencyTracking:
              freqtrdial->value(value);
              freqtrdial->selection_color(setKnob(value,FILTDEF::freqTrack.def));
              break;

          case FILTERINSERT::control::velocitySensitivity:
          {
              vsnsadial->value(value);
              if (isVoice)
                  vsnsadial->selection_color(setKnob(value,FILTDEF::voiceVelSense.def));
              else
                  vsnsadial->selection_color(setKnob(value,FILTDEF::velSense.def));
              if (velsnsamp != NULL)
                  *velsnsamp = value;
              break;
          }

          case FILTERINSERT::control::velocityCurve:
              vsnsdial->value(value);
              vsnsdial->selection_color(setKnob(value,FILTDEF::velFuncSense.def));
              if (velsns != NULL)
                  *velsns = value;
              break;

          case FILTERINSERT::control::gain:
              gaindial->value(value);
              gaindial->selection_color(setKnob(value,FILTDEF::gain.def));
              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));
              refresh();
              break;

          case FILTERINSERT::control::analogType:
              analogfiltertypechoice->value(value_int);
              if (value_int < 2)
                  qdial->deactivate();
              else
                  qdial->activate();
              updateVCforQ();
              break;

          case FILTERINSERT::control::stateVariableType:
              svfiltertypechoice->value(value_int);
              break;

          case FILTERINSERT::control::frequencyTrackingRange:
              freqtrackoffset->value(value_int);
              freqtrdial->setValueType(getFilterFreqTrackType(value));
              if (value_int)
              {
                  freqtracknormal->hide();
                  freqtrackchecked->show();
              }
              else
              {
                  freqtracknormal->show();
                  freqtrackchecked->hide();
              }
              break;

          case FILTERINSERT::control::formantSlowness:
              if (!fromUs)
              {
                  frsldial->value(value);
                  frsldial->selection_color(setKnob(value,FILTDEF::formSpeed.def));
              }
              break;

          case FILTERINSERT::control::formantClearness:
              if (!fromUs)
              {
                  wvknob->value(value);
                  wvknob->selection_color(setKnob(value,findDynClearDef()));
              }
              break;

          case FILTERINSERT::control::formantFrequency:
              if (isCurrent)
              {
                  if (!fromUs)
                  {
                      formant_freq_dial->value(value);
                      formant_freq_dial->selection_color(setKnob(value,findDynDef(0))); // has pseudo default
                  }
                  formantfiltergraph->redraw();
              }
              break;

          case FILTERINSERT::control::formantQ:
              if (isCurrent)
              {
                  if (!fromUs)
                  {
                      formant_q_dial->value(value);
                      formant_q_dial->selection_color(setKnob(value,FILTDEF::formQ.def));
                  }
                  formantfiltergraph->redraw();
              }
              break;

          case FILTERINSERT::control::formantAmplitude:
              if (isCurrent)
              {
                  if (!fromUs)
                  {
                      formant_amp_dial->value(value);
                      formant_amp_dial->selection_color(setKnob(value,FILTDEF::formAmp.def));
                  }
                  formantfiltergraph->redraw();
              }
              break;

          case FILTERINSERT::control::formantStretch:
              if (!fromUs)
              {
                  strchdial->value(value);
                  strchdial->selection_color(setKnob(value,FILTDEF::formStretch.def));
              }
              break;

          case FILTERINSERT::control::formantCenter:
              cfknob->value(value*5);
              cfknob->selection_color(setSlider(value,64));
              centerfreqvo->do_callback();
              formantfiltergraph->redraw();
              break;

          case FILTERINSERT::control::formantOctave:
              octknob->value(value*5);
              octknob->selection_color(setSlider(value,64));
              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();
              check_vowel();
              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();
              check_vowel();
              formantfiltergraph->redraw();
              break;

          case FILTERINSERT::control::sequencePosition:
              update_formant_window();
              check_vowel();
              break;

          case FILTERINSERT::control::vowelPositionInSequence:
              vowel_counter->value(value_int);
              update_formant_window();
              check_vowel();
              formantfiltergraph->redraw();
              break;

          case FILTERINSERT::control::negateInput:
              neginput->value(value != 0);
              break;
      }
}

float FilterUI::findDynDef(int type) {
  // types freq 0, q 1, amp 2
                  float val;
                  if (type == 0)
                      val = formFreqDef; // standard default;
                  else
                      val = FILTDEF::formAmp.def; // standard default
                  if (dynFilt)
                  {
                      //std::cout << "is dyn" << std::endl;
                      if (dynPreset == 3)
                      {
                          if (nvowel == 0)
                          {
                              switch (nformant)
                              {
                                  case 0:
                                      if (type == 0)
                                          val = DYNform::Preset3V0F0.freq;
                                      else
                                          val = DYNform::Preset3V0F0.amp;
                                      break;
                                  case 1:
                                      if (type == 0)
                                          val = DYNform::Preset3V0F1.freq;
                                      else
                                          val = DYNform::Preset3V0F1.amp;
                                      break;
                                  case 2:
                                      if (type == 0)
                                          val = DYNform::Preset3V0F2.freq;
                                      else
                                          val = DYNform::Preset3V0F2.amp;
                                      break;
                              }
                          }
                          else if (nvowel == 1)
                          {
                              switch (nformant)
                              {
                                  case 0:
                                      if (type == 0)
                                          val = DYNform::Preset3V1F0.freq;
                                      else
                                          val = DYNform::Preset3V1F0.amp;
                                      break;
                                  case 1:
                                      if (type == 0)
                                          val = DYNform::Preset3V1F1.freq;
                                      else
                                          val = DYNform::Preset3V1F1.amp;
                                      break;
                                  case 2:
                                      if (type == 0)
                                          val = DYNform::Preset3V1F2.freq;
                                      else
                                          val = DYNform::Preset3V1F2.amp;
                                      break;
                              }
                          }
                      }

                      else if (dynPreset == 4)
                      {
                          if (nvowel == 0)
                          {
                              switch (nformant)
                              {
                                  case 0:
                                      if (type == 0)
                                          val = DYNform::Preset4V0F0.freq;
                                      else
                                          val = DYNform::Preset4V0F0.amp;
                                      break;
                                  case 1:
                                      if (type == 0)
                                          val = DYNform::Preset4V0F1.freq;
                                      else
                                          val = DYNform::Preset4V0F1.amp;
                                      break;
                              }
                          }
                          else if (nvowel == 1)
                          {
                              switch (nformant)
                              {
                                  case 0:
                                      if (type == 0)
                                          val = DYNform::Preset4V1F0.freq;
                                      else
                                          val = DYNform::Preset4V1F0.amp;
                                      break;
                                  case 1:
                                      if (type == 0)
                                          val = DYNform::Preset4V1F1.freq;
                                      else
                                          val = DYNform::Preset4V1F1.amp;
                                      break;
                              }
                          }
                      }
                  }
                  return val;
  ;
}

float FilterUI::findDynClearDef() {
  //
             if (dynFilt && dynPreset == 4)
                 return 0;
             return FILTDEF::formClear.def;;
  ;
}

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_;
      dynFilt = false;
      dynPreset = 0;
      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));

      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);
              break;
      }
}
