# data file for the Fltk User Interface Designer (fluid)
version 1.0308
header_name {.h}
code_name {.cc}
comment {FilterUI.h} {not_in_source in_header
}

comment {FilterUI.cc} {in_source not_in_header
}

comment {Original ZynAddSubFX author Nasca Octavian Paul
Copyright (C) 2002-2005 Nasca Octavian Paul
Copyright 2009-2011, Alan Calvert
Copyright 2016-2024 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

} {selected in_source in_header
}

decl {\#include <iostream>} {public local
}

decl {\#include "globals.h"} {public local
}

decl {\#include "UI/MiscGui.h"} {public local
}

decl {\#include "UI/WidgetCheckButton.h"} {public local
}

decl {\#include "UI/WidgetPDial.h"} {public local
}

decl {\#include "UI/WidgetMWSlider.h"} {public local
}

decl {\#include <FL/Fl_Group.H>} {public local
}

decl {\#include <FL/Fl_Box.H>} {public local
}

decl {\#include <FL/fl_draw.H>} {public local
}

decl {\#include <FL/fl_ask.H>} {public local
}

decl {\#include "PresetsUI.h"} {public local
}

decl {\#include "Params/FilterParams.h"} {public local
}

decl {\#include <FL/Fl.H>} {private global
}

decl {\#include <FL/names.h>} {private global
}

decl {\#include "MasterUI.h"} {private global
}

decl {\#include "Misc/SynthEngine.h"} {public global
}

decl {class FilterUI;} {public global
}

decl {\#include "Misc/TextMsgBuffer.h"

    namespace { // Implementation details...
        TextMsgBuffer& textMsgBuffer = TextMsgBuffer::instance();
    }} {private local
}

decl {\#include "Misc/FormatFuncs.h"
    using func::asString;} {private local
}

decl {\#include "Misc/NumericFuncs.h"
    using func::asDecibel;
    using func::limit;} {private local
}

class FormantFilterGraph {: {public Fl_Box}
} {
  Function {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_)} {} {
    code {//
        selectedFormant = -1;
        hoverFormant = -1;
        qMode = false;
        graphpoints = new float [w];} {}
  }
  Function {draw_freq_line(float freq)} {} {
    code {//
        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());} {}
  }
  Function {draw()} {} {
    code {//
        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);

        /*  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;
        }
        */} {}
  }
  Function {~FormantFilterGraph()} {} {
    code {delete [] graphpoints;} {}
  }
  decl {FilterUI& parent;} {private local
  }
  decl {FilterParams *pars;} {private local
  }
  decl {int const *nvowel, *nformant;} {private local
  }
  decl {float *graphpoints;} {private local
  }
  decl {int selectedFormant, hoverFormant, yRef, xRef, qRef, ampRef, freqRef, cFreqRef;} {private local
  }
  decl {bool qMode;} {private local
  }
  Function {handle(int event)} {return_type int
  } {
    code {//
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);} {}
  }
  Function {delegate(Fl_Valuator* w, int value)} {private return_type void
  } {
    code {// If widget value has changed, update and perform manual callback

        if (w->value() != value + 1)
        {
            w->value(value + 1);
            w->do_callback();
        }} {}
  }
  Function {update_refs()} {private return_type {inline void}
  } {
    code {//
        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;} {}
  }
}

class FilterUI {: {public Fl_Group,PresetsUI_}
} {
  Function {FilterUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} {
    code {//
        synth = NULL;
        pars=NULL;
        velsnsamp=NULL;
        velsns=NULL;
        nvowel = 0;
        nformant = 0;
        nseqpos = 0;
        nseqsize = 3;
        nVoCount = 0;
        nFoCount = 0;
        formFreqDef = -1;} {}
  }
  Function {~FilterUI()} {} {
    code {filterui->hide();
        formantparswindow->hide();
        hide();
        delete (formantparswindow);} {}
  }
  Function {make_window()} {} {
    Fl_Window filterui {
      xywh {460 79 275 75} type Double color 50 labelfont 1 labelsize 12 hide
      class Fl_Group
    } {
      Fl_Group filterparamswindow {
        xywh {0 0 275 75} box PLASTIC_UP_BOX color 223 labelfont 1 labelsize 10 labelcolor 64 align 17
      } {
        Fl_Choice analogfiltertypechoice {
          label FilterType
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::analogType, o->value(), TOPLEVEL::type::Write);}
          tooltip {The Filter type} xywh {5 43 58 15} down_box BORDER_BOX selection_color 64 labelsize 10 labelcolor 64 align 6 textfont 1 textsize 10 textcolor 64
          code1 {o->value(pars->Ptype);}
          code2 {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 svfiltertypechoice {
          label FilterType
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::stateVariableType, o->value(), TOPLEVEL::type::Write);}
          tooltip {The Filter type} xywh {5 43 58 15} down_box BORDER_BOX selection_color 64 labelsize 10 labelcolor 64 align 6 textfont 1 textsize 10 textcolor 64
          code1 {o->value(pars->Ptype);}
          code2 {o->add("Low");o->add("High");o->add("Band");o->add("Stop");}
        } {}
        Fl_Choice filtertype {
          label Category
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::baseType, o->value(), TOPLEVEL::type::Write);}
          tooltip {The Category of the Filter (Analog/Formantic/etc.)} xywh {5 10 66 15} down_box BORDER_BOX selection_color 64 labelsize 10 labelcolor 64 align 6 textfont 1 textsize 10 textcolor 64
          code0 {o->value(pars->Pcategory);}
          code1 {o->add("analog");o->add("formant");o->add("StVarF");}
        } {}
        Fl_Dial cfreqdial {
          label { C.Freq}
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::centerFrequency, o->value(), TOPLEVEL::type::Write);}
          tooltip {Center Frequency of the Filter or the base position in the vowel's sequence} xywh {65 28 30 30} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
          code0 {o->value(pars->Pfreq);}
          code1 {o->setValueType(getFilterFreqType(filtertype->value()));}
          class WidgetPDial
        }
        Fl_Dial qdial {
          label Q
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::Q, o->value(), TOPLEVEL::type::Write);}
          tooltip {Filter resonance or bandwidth} xywh {100 28 30 30} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127 deactivate
          class WidgetPDial
        }
        Fl_Dial freqtrdial {
          label {Freq.tr.}
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::frequencyTracking, o->value(), TOPLEVEL::type::Write);}
          tooltip {Filter frequency tracking} xywh {240 28 30 30} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
          code1 {o->value(pars->Pfreqtrack);}
          class WidgetPDial
        }
        Fl_Dial vsnsadial {
          label {V.Sns.}
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::velocitySensitivity, o->value(), TOPLEVEL::type::Write);}
          tooltip {Velocity sensing amount of the Filter} xywh {135 28 30 30} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
          code0 {o->setValueType(VC_FilterVelocityAmp);}
          class WidgetPDial
        }
        Fl_Dial vsnsdial {
          label { VF.Sns.}
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::velocityCurve, o->value(), TOPLEVEL::type::Write);}
          tooltip {Velocity Sensing Function of the Filter} xywh {170 28 30 30} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
          code0 {o->setValueType(VC_FilterVelocitySense);}
          code1 {o->setGraphicsType(VC_FilterVelocitySense);}
          class WidgetPDial
        }
        Fl_Dial gaindial {
          label Gain
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::gain, o->value(), TOPLEVEL::type::Write);}
          tooltip {Filter output gain/damp} xywh {205 28 30 30} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
          code0 {o->value(pars->Pgain);}
          code1 {o->setValueType(VC_FilterGain);}
          class WidgetPDial
        }
        Fl_Counter stcounter {
          label {St.}
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::stages, o->value() - 1, TOPLEVEL::type::Write);}
          tooltip {Filter stages (in order to increase dB/oct. value and the order of the filter)} xywh {73 10 41 15} type Simple selection_color 64 labelsize 10 labelcolor 64 align 8 minimum 1 maximum 5 step 1 value 1 textfont 1 textsize 10 textcolor 64
        }
      }
      Fl_Text_Display filterparamslabel {
        label Parameters
        xywh {135 14 50 4} box NO_BOX labelfont 1 labelsize 10 labelcolor 64
      }
      Fl_Button editbutton {
        label Edit
        callback {//
    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();}
        xywh {5 40 52 26} box GTK_THIN_UP_BOX selection_color 221 labelfont 1 labelsize 11 labelcolor 64
      }
      Fl_Button filtC {
        label C
        callback {//
            synth->getGuiMaster()->getPresetsUi()->Ucopy(npart, kititem, engine, TOPLEVEL::insert::filterGroup);
            ;}
        xywh {202 8 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 197
      }
      Fl_Button filtP {
        label P
        callback {//
            synth->getGuiMaster()->getPresetsUi()->Upaste(npart, kititem, engine, TOPLEVEL::insert::filterGroup);
            ;}
        xywh {220 8 15 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 10 labelcolor 197
      }
      Fl_Check_Button freqtrackoffset {
        callback {//
        int tmp = (o->value() != 0);
        send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::frequencyTrackingRange, tmp, TOPLEVEL::type::Write);}
        tooltip {Set frequency tracking range to 0%-200%} xywh {236 10 16 16} down_box DOWN_BOX selection_color 64 labelcolor 64 align 24
        class Fl_Check_Button2
      }
      Fl_Text_Display freqtracknormal {
        label {- /+}
        xywh {242 24 44 4} box NO_BOX selection_color 64 labelsize 10 labelcolor 64 textsize 10 textcolor 64
      }
      Fl_Text_Display freqtrackchecked {
        label {0/+}
        xywh {242 24 44 4} box NO_BOX selection_color 64 labelsize 10 labelcolor 64 textsize 10 textcolor 64 hide
      }
    }
  }
  Function {make_formant_window()} {} {
    Fl_Window formantparswindow {
      label {Formant Filter Parameters}
      callback {formClose->do_callback();}
      xywh {186 150 700 205} type Double labelfont 1 labelsize 12 hide resizable
      code0 {formantDW = o->w(); formantDH = o->h();}
      code1 {o->size_range(formantDW, formantDH, 0, 0, 0, 0, 1);}
    } {
      Fl_Group {} {
        xywh {1 1 698 203} box ENGRAVED_FRAME
      } {
        Fl_Group {} {
          xywh {485 47 105 113} box THIN_UP_FRAME
        } {
          Fl_Counter formantnumber {
            label {Formant }
            callback {//
          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);}
            xywh {545 80 40 15} type Simple selection_color 64 labelfont 1 labelsize 10 labelcolor 64 align 4 minimum 1 maximum 127 step 1 value 1 textsize 10 textcolor 64
            code0 {o->bounds(1,FF_MAX_FORMANTS);}
            code1 {o->value(nformant + 1);}
          }
          Fl_Counter vowelnumber {
            callback {//
          nvowel = int(o->value() - 1);

          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::vowelNumber, nvowel, TOPLEVEL::type::Write);}
            xywh {545 55 40 20} type Simple selection_color 64 labelfont 1 labelsize 10 labelcolor 64 align 4 minimum 1 maximum 127 step 1 value 1 textfont 1 textsize 11 textcolor 64
            code0 {o->bounds(1,FF_MAX_VOWELS);}
            code1 {o->value(nvowel + 1);}
          }
          Fl_Box vowelpatch {
            label {Vowel no.}
            xywh {487 56 56 18} box FLAT_BOX labelfont 1 labelsize 10 labelcolor 64
          }
          Fl_Group formantparsgroup {
            xywh {490 105 95 50} box ENGRAVED_FRAME
          } {
            Fl_Dial formant_freq_dial {
              label Freq
              callback {//
            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);}
              tooltip {Formant frequency} xywh {495 115 25 25} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
              class WidgetPDial
            }
            Fl_Dial formant_q_dial {
              label Q
              callback {//
            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);}
              tooltip {Formant's Q} xywh {525 115 24 25} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
              class WidgetPDial
            }
            Fl_Dial formant_amp_dial {
              label Amp
              callback {//
            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);}
              tooltip {Formant amplitude} xywh {555 115 24 25} box ROUND_UP_BOX labelsize 10 labelcolor 64 maximum 127
              class WidgetPDial
            }
          }
        }
        Fl_Group {} {
          xywh {590 47 104 113} box THIN_UP_BOX
        } {
          Fl_Counter seqsize {
            label {Seq.Size}
            callback {//
          nseqsize = o->value();
          if (nseqpos > nseqsize)
          {
              nseqpos = nseqsize;
              seqpos->value(nseqpos);
          }


          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::sequenceSize, nseqsize, TOPLEVEL::type::Write);}
            xywh {614 62 54 18} type Simple selection_color 64 labelfont 1 labelsize 10 labelcolor 64 align 5 minimum 1 maximum 127 step 1 value 1 textfont 1 textsize 11 textcolor 64
            code0 {o->bounds(1,FF_MAX_SEQUENCE);}
            code1 {o->value(nseqsize);}
          }
          Fl_Counter seqpos {
            label {S.Pos.}
            callback {//
          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);}
            tooltip {Current position in the sequence} xywh {596 98 40 15} type Simple selection_color 64 labelfont 1 labelsize 10 labelcolor 64 align 9 minimum 1 maximum 127 step 1 value 1 textsize 10 textcolor 64
            code0 {o->bounds(1,FF_MAX_SEQUENCE);}
            code1 {o->value(nseqpos + 1);}
          }
          Fl_Counter vowel_counter {
            label Vowel
            callback {//
          nVoCount = o->value() - 1;

          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::vowelPositionInSequence, nVoCount, TOPLEVEL::type::Write, nseqpos);}
            tooltip {Vowel number at the sequence position} xywh {648 98 40 15} type Simple selection_color 64 labelsize 10 labelcolor 64 align 1 minimum 1 maximum 127 step 1 value 1 textsize 10 textcolor 64
            code0 {o->bounds(1,FF_MAX_VOWELS);}
          }
          Fl_Check_Button neginput {
            label {Neg.Input}
            callback {//
          send_data(TOPLEVEL::action::forceUpdate, FILTERINSERT::control::negateInput, o->value(), TOPLEVEL::type::Write);}
            tooltip {Negate the input from LFO/envelopes/etc.} xywh {628 132 60 20} down_box DOWN_BOX selection_color 64 labelsize 10 labelcolor 64
            code0 {o->value(pars->Psequencereversed);}
            class Fl_Check_Button2
          }
          Fl_Dial strchdial {
            label Stretch
            callback {//
          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);}
            tooltip {Sequence Stretch} xywh {595 130 25 25} box ROUND_UP_BOX labelsize 10 labelcolor 64 align 5 maximum 127
            code0 {o->value(pars->Psequencestretch);}
            code1 {o->setValueType(VC_FormFilterStretch);}
            class WidgetPDial
          }
        }
        Fl_Counter formantcount {
          label Formants
          callback {//
        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);}
          xywh {485 19 65 20} type Simple selection_color 64 labelsize 12 labelcolor 64 align 1 minimum 1 maximum 127 step 1 value 1 textsize 12 textcolor 64
          code0 {o->bounds(1,FF_MAX_FORMANTS);}
        }
        Fl_Dial frsldial {
          label {Fr.Sl.}
          callback {//
        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);}
          tooltip {Formant's Slowness (Morphing)} xywh {565 15 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 labelcolor 64 align 1 maximum 127
          code0 {o->value(pars->Pformantslowness);}
          code1 {o->setValueType(VC_FormFilterSlowness);}
          class WidgetPDial
        }
        Fl_Value_Output centerfreqvo {
          label {C.f.}
          callback {o->value(pars->getcenterfreq()/1000.0);}
          tooltip {Center Frequency (kHz)} xywh {512 164 35 16} box THIN_DOWN_BOX labelsize 12 labelcolor 64 when 3 minimum 1 maximum 127 step 0.1 value 64 textfont 1 textsize 11 textcolor 64
          code0 {o->step(0.01, 1);}
          code1 {o->value(pars->getcenterfreq()/1000.0);}
        }
        Fl_Value_Output octavesfreqvo {
          label {Oct.}
          callback {o->value(lrintf(pars->getoctavesfreq()));}
          tooltip {No. of octaves} xywh {512 185 35 16} box THIN_DOWN_BOX labelsize 12 labelcolor 64 when 3 minimum 1 maximum 127 step 1 value 5 textfont 1 textsize 11 textcolor 64
          code0 {o->step(1, 1);}
          code1 {o->value(pars->getoctavesfreq());}
        }
        Fl_Slider cfknob {
          callback {//
        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);}
          xywh {547 164 89 16} type {Horz Knob} box THIN_DOWN_BOX labelcolor 64 maximum 635 step 1 value 1
          code0 {o->value(pars->Pcenterfreq*5);}
          code1 {o->selection_color(setSlider(pars->Pcenterfreq,FILTDEF::formCentre.def));}
          class mwheel_slider_rev
        }
        Fl_Slider octknob {
          callback {//
        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);}
          xywh {547 185 90 16} type {Horz Knob} box THIN_DOWN_BOX labelcolor 64 maximum 635 step 1 value 5
          code0 {o->value(pars->Poctavesfreq*5);}
          code1 {o->selection_color(setSlider(pars->Poctavesfreq,FILTDEF::formOctave.def));}
          class mwheel_slider_rev
        }
        Fl_Dial wvknob {
          label {Vw.Cl.}
          callback {//
        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);}
          tooltip {Vowel "clearness" (transition between vowels)} xywh {600 15 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 labelcolor 64 align 1 maximum 127
          code0 {o->value(pars->Pvowelclearness);}
          code1 {o->setValueType(VC_FormFilterClearness);}
          code2 {o->setGraphicsType(VC_FormFilterClearness);}
          class WidgetPDial
        }
        Fl_Button formClose {
          label Close
          callback {//
    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;}
          xywh {643 170 50 25} box THIN_UP_BOX color 196 labelcolor 64
        }
        Fl_Button formCopy {
          label C
          callback {//
              synth->getGuiMaster()->getPresetsUi()->Ucopy(npart, kititem, engine, TOPLEVEL::insert::filterGroup,0, nvowel);
              // dummy parameter always stores all possible formants
              ;}
          xywh {635 25 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 197
        }
        Fl_Button formPaste {
          label P
          callback {//
              synth->getGuiMaster()->getPresetsUi()->Upaste(npart, kititem, engine, TOPLEVEL::insert::filterGroup,0, nvowel);
              // dummy parameter always stores all possible formants
              ;}
          xywh {665 25 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 197
        }
        Fl_Box formvowel {
          label Vowel
          xywh {635 8 55 15} labelcolor 64
        }
        Fl_Box {} {
          xywh {630 4 64 40} box EMBOSSED_FRAME
        }
      }
    }
    code {// 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} {}
  }
  Function {update_formant_window()} {} {
    code {//
        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);} {}
  }
  Function {check_vowel()} {} {
    code {//
        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();} {}
  }
  Function {refresh()} {} {
    code {//
        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();} {}
  }
  Function {filterRtext(float dScale)} {} {
    code {//
            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);} {}
  }
  Function {theme()} {} {
    code {//
        if(formantparswindow)
        {
            if(formantparswindow->visible())
            {
                lastformantX = 0;
                formantRtext();
                formantparswindow->redraw();
            }
        }
        ;} {}
  }
  Function {formantRtext()} {} {
    code {//
    /*
     * 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);} {}
  }
  Function {send_data(int action, int control, float value, int type, int parameter = UNUSED, int offset = UNUSED)} {} {
    code {//
        type |= TOPLEVEL::type::Write;
        collect_writeData(synth, value, action, type, control, npart, kititem, engine, TOPLEVEL::insert::filterGroup, parameter, offset);} {}
  }
  Function {fetchData(float value, int control, int part, int kititem = UNUSED, int engine = UNUSED, int insert = UNUSED, int parameter = UNUSED, int offset = UNUSED, int miscmsg = UNUSED, int request = UNUSED)} {return_type float
  } {
    code {//
        return collect_readData(synth, value, control, part, kititem, engine, insert, parameter, offset, miscmsg, request);} {}
  }
  Function {returns_update(CommandBlock *getData)} {} {
    code {//
    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;
    }} {}
  }
  Function {findDynDef(int type)} {return_type float
  } {
    code {// 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;
;} {}
  }
  Function {findDynClearDef()} {return_type float
  } {
    code {//
           if (dynFilt && dynPreset == 4)
               return 0;
           return FILTDEF::formClear.def;;
;} {}
  }
  Function {init(FilterParams *filterpars_,unsigned char *velsnsamp_,unsigned char *velsns_, int npart_, int kititem_, int engine_)} {} {
    code {//
    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();} {}
  }
  Function {updateVCforQ()} {return_type void
  } {
    code {//
    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;
    }} {}
  }
  decl {FormantFilterGraph *formantfiltergraph;} {public local
  }
  decl {FilterParams *pars;} {private local
  }
  decl {unsigned char *velsnsamp,*velsns;} {private local
  }
  decl {int nvowel,nformant,nseqpos, nseqsize, nVoCount, nFoCount;} {private local
  }
  decl {SynthEngine *synth;} {private local
  }
  decl {int npart;} {private local
  }
  decl {int kititem;} {private local
  }
  decl {int engine;} {private local
  }
  decl {bool dynFilt;} {private local
  }
  decl {int dynPreset;} {private local
  }
  decl {int formantDW;} {private local
  }
  decl {int formantDH;} {private local
  }
  decl {int lastformantX;} {private local
  }
  decl {int lastformantY;} {private local
  }
  decl {int lastformantW;} {private local
  }
  decl {bool formantSeen;} {private local
  }
  decl {float formFreqDef;} {private local
  }
}
