package com.domemusictechnologies.bigrat;


import voltage.controllers.*;
import voltage.core.*;
import voltage.core.Jack.JackType;
import voltage.sources.*;
import voltage.utility.*;
import voltage.processors.*;
import voltage.effects.*;
import java.awt.*;

//[user-imports]   Add your own imports here
import static java.lang.Math.round; // Round double to nearest integer value
import static java.lang.Math.pow;   // Raise to power method, used for V/oct calc
import static java.lang.Math.exp;   // e to the power x method, used for RC time constant calc

//[/user-imports]


public class BigRat extends VoltageModule
//[user-inheritance]
//[/user-inheritance]
{

public BigRat( long moduleID, VoltageObjects voltageObjects )
{
   super( moduleID, voltageObjects, "Big Rat", ModuleType.ModuleType_Oscillators, 2.0 );

   InitializeControls();


   canBeBypassed = false;
   SetSkin( "72f60a75d6c4416fa667ea17b2cf5626" );
}

void InitializeControls()
{

   gateInSocket = new VoltageAudioJack( "Gate Input", "Gate In", this, JackType.JackType_AudioInput );
   AddComponent( gateInSocket );
   gateInSocket.SetWantsMouseNotifications( false );
   gateInSocket.SetPosition( 6, 45 );
   gateInSocket.SetSize( 25, 25 );
   gateInSocket.SetSkin( "Jack Round 25px" );

   gateContSwitch = new VoltageSwitch( "Gate Mode", "Gate / Cont", this, 0 );
   AddComponent( gateContSwitch );
   gateContSwitch.SetWantsMouseNotifications( false );
   gateContSwitch.SetPosition( 64, 44 );
   gateContSwitch.SetSize( 15, 27 );
   gateContSwitch.SetSkin( "2-State Slide Vertical" );

   gateButton = new VoltageButton( "Gate Button", "Manual Trigger", this );
   AddComponent( gateButton );
   gateButton.SetWantsMouseNotifications( false );
   gateButton.SetPosition( 105, 43 );
   gateButton.SetSize( 30, 30 );
   gateButton.SetSkin( "Square PM Blue" );
   gateButton.ShowOverlay( false );
   gateButton.SetOverlayText( "" );
   gateButton.SetAutoRepeat( false );

   riseTimeKnob = new VoltageKnob( "Attack", "Rise Time", this, 0.001, 10.0, 1.0 );
   AddComponent( riseTimeKnob );
   riseTimeKnob.SetWantsMouseNotifications( false );
   riseTimeKnob.SetPosition( 30, 93 );
   riseTimeKnob.SetSize( 25, 25 );
   riseTimeKnob.SetSkin( "ARP2500 Sm Blue" );
   riseTimeKnob.SetRange( 0.001, 10.0, 1.0, false, 0 );
   riseTimeKnob.SetKnobParams( 215, 145 );
   riseTimeKnob.DisplayValueInPercent( false );
   riseTimeKnob.SetKnobAdjustsRing( true );
   riseTimeKnob.SetMidpointValue( 1.0 );

   riseCurveKnob = new VoltageKnob( "Rise Curve Knob", "Rise Curve Shape", this, 0.0, 10.0, 0.0 );
   AddComponent( riseCurveKnob );
   riseCurveKnob.SetWantsMouseNotifications( false );
   riseCurveKnob.SetPosition( 88, 93 );
   riseCurveKnob.SetSize( 25, 25 );
   riseCurveKnob.SetSkin( "ARP2500 Sm Emerald" );
   riseCurveKnob.SetRange( 0.0, 10.0, 0.0, false, 0 );
   riseCurveKnob.SetKnobParams( 215, 145 );
   riseCurveKnob.DisplayValueInPercent( false );
   riseCurveKnob.SetKnobAdjustsRing( true );

   fallTimeKnob = new VoltageKnob( "Decay", "Fall Time", this, 0.001, 10.0, 1.0 );
   AddComponent( fallTimeKnob );
   fallTimeKnob.SetWantsMouseNotifications( false );
   fallTimeKnob.SetPosition( 30, 211 );
   fallTimeKnob.SetSize( 25, 25 );
   fallTimeKnob.SetSkin( "ARP2500 Sm Blue" );
   fallTimeKnob.SetRange( 0.001, 10.0, 1.0, false, 0 );
   fallTimeKnob.SetKnobParams( 215, 145 );
   fallTimeKnob.DisplayValueInPercent( false );
   fallTimeKnob.SetKnobAdjustsRing( true );
   fallTimeKnob.SetMidpointValue( 1.0 );

   fallCurveKnob = new VoltageKnob( "Fall Curve Shape", "Fall Curve Shape", this, 0.0, 10.0, 0.0 );
   AddComponent( fallCurveKnob );
   fallCurveKnob.SetWantsMouseNotifications( false );
   fallCurveKnob.SetPosition( 88, 211 );
   fallCurveKnob.SetSize( 25, 25 );
   fallCurveKnob.SetSkin( "ARP2500 Sm Emerald" );
   fallCurveKnob.SetRange( 0.0, 10.0, 0.0, false, 0 );
   fallCurveKnob.SetKnobParams( 215, 145 );
   fallCurveKnob.DisplayValueInPercent( false );
   fallCurveKnob.SetKnobAdjustsRing( true );

   riseTimeCV = new VoltageAudioJack( "Rise Time CV In", "Rise Time CV In", this, JackType.JackType_AudioInput );
   AddComponent( riseTimeCV );
   riseTimeCV.SetWantsMouseNotifications( false );
   riseTimeCV.SetPosition( 30, 122 );
   riseTimeCV.SetSize( 25, 25 );
   riseTimeCV.SetSkin( "Jack Round Blue Ring" );

   riseCurveCV = new VoltageAudioJack( "Rise Curve CV In", "Rise Curve CV In", this, JackType.JackType_AudioInput );
   AddComponent( riseCurveCV );
   riseCurveCV.SetWantsMouseNotifications( false );
   riseCurveCV.SetPosition( 88, 122 );
   riseCurveCV.SetSize( 25, 25 );
   riseCurveCV.SetSkin( "Jack Round Green Ring" );

   fallTimeCV = new VoltageAudioJack( "Fall Time CV", "Fall Time CV In", this, JackType.JackType_AudioInput );
   AddComponent( fallTimeCV );
   fallTimeCV.SetWantsMouseNotifications( false );
   fallTimeCV.SetPosition( 30, 240 );
   fallTimeCV.SetSize( 25, 25 );
   fallTimeCV.SetSkin( "Jack Round Blue Ring" );

   fallCurveCV = new VoltageAudioJack( "Fall Curve CV In", "Fall Curve CV In", this, JackType.JackType_AudioInput );
   AddComponent( fallCurveCV );
   fallCurveCV.SetWantsMouseNotifications( false );
   fallCurveCV.SetPosition( 88, 240 );
   fallCurveCV.SetSize( 25, 25 );
   fallCurveCV.SetSkin( "Jack Round Green Ring" );

   polaritySwitch = new VoltageSwitch( "Polarity Switch", "Output Polarity", this, 1 );
   AddComponent( polaritySwitch );
   polaritySwitch.SetWantsMouseNotifications( false );
   polaritySwitch.SetPosition( 10, 288 );
   polaritySwitch.SetSize( 15, 27 );
   polaritySwitch.SetSkin( "2-State Slide Vertical" );

   outputSocket = new VoltageAudioJack( "Curve Output", "Curve Output", this, JackType.JackType_AudioOutput );
   AddComponent( outputSocket );
   outputSocket.SetWantsMouseNotifications( false );
   outputSocket.SetPosition( 109, 290 );
   outputSocket.SetSize( 25, 25 );
   outputSocket.SetSkin( "Jack Round Sky Ring" );

   textLabel1 = new VoltageLabel( "textLabel1", "textLabel1", this, "B.I.G.R.A.T." );
   AddComponent( textLabel1 );
   textLabel1.SetWantsMouseNotifications( false );
   textLabel1.SetPosition( 32, 0 );
   textLabel1.SetSize( 80, 17 );
   textLabel1.SetEditable( false, false );
   textLabel1.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel1.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel1.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel1.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel1.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel1.SetBorderSize( 1 );
   textLabel1.SetMultiLineEdit( false );
   textLabel1.SetIsNumberEditor( false );
   textLabel1.SetNumberEditorRange( 0, 100 );
   textLabel1.SetNumberEditorInterval( 1 );
   textLabel1.SetNumberEditorUsesMouseWheel( false );
   textLabel1.SetHasCustomTextHoverColor( false );
   textLabel1.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel1.SetFont( "Verdana", 14, true, false );

   textLabel2 = new VoltageLabel( "textLabel2", "textLabel2", this, "Rise Time" );
   AddComponent( textLabel2 );
   textLabel2.SetWantsMouseNotifications( false );
   textLabel2.SetPosition( 15, 78 );
   textLabel2.SetSize( 53, 13 );
   textLabel2.SetEditable( false, false );
   textLabel2.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel2.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel2.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel2.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel2.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel2.SetBorderSize( 1 );
   textLabel2.SetMultiLineEdit( false );
   textLabel2.SetIsNumberEditor( false );
   textLabel2.SetNumberEditorRange( 0, 100 );
   textLabel2.SetNumberEditorInterval( 1 );
   textLabel2.SetNumberEditorUsesMouseWheel( false );
   textLabel2.SetHasCustomTextHoverColor( false );
   textLabel2.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel2.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel3 = new VoltageLabel( "textLabel3", "textLabel3", this, "Curve" );
   AddComponent( textLabel3 );
   textLabel3.SetWantsMouseNotifications( false );
   textLabel3.SetPosition( 81, 78 );
   textLabel3.SetSize( 37, 14 );
   textLabel3.SetEditable( false, false );
   textLabel3.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel3.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel3.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel3.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel3.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel3.SetBorderSize( 1 );
   textLabel3.SetMultiLineEdit( false );
   textLabel3.SetIsNumberEditor( false );
   textLabel3.SetNumberEditorRange( 0, 100 );
   textLabel3.SetNumberEditorInterval( 1 );
   textLabel3.SetNumberEditorUsesMouseWheel( false );
   textLabel3.SetHasCustomTextHoverColor( false );
   textLabel3.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel3.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel4 = new VoltageLabel( "textLabel4", "textLabel4", this, "CV In" );
   AddComponent( textLabel4 );
   textLabel4.SetWantsMouseNotifications( false );
   textLabel4.SetPosition( 53, 240 );
   textLabel4.SetSize( 36, 26 );
   textLabel4.SetEditable( false, false );
   textLabel4.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel4.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel4.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel4.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel4.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel4.SetBorderSize( 1 );
   textLabel4.SetMultiLineEdit( false );
   textLabel4.SetIsNumberEditor( false );
   textLabel4.SetNumberEditorRange( 0, 100 );
   textLabel4.SetNumberEditorInterval( 1 );
   textLabel4.SetNumberEditorUsesMouseWheel( false );
   textLabel4.SetHasCustomTextHoverColor( false );
   textLabel4.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel4.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel5 = new VoltageLabel( "textLabel5", "textLabel5", this, "Fall Time" );
   AddComponent( textLabel5 );
   textLabel5.SetWantsMouseNotifications( false );
   textLabel5.SetPosition( 17, 193 );
   textLabel5.SetSize( 53, 17 );
   textLabel5.SetEditable( false, false );
   textLabel5.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel5.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel5.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel5.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel5.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel5.SetBorderSize( 1 );
   textLabel5.SetMultiLineEdit( false );
   textLabel5.SetIsNumberEditor( false );
   textLabel5.SetNumberEditorRange( 0, 100 );
   textLabel5.SetNumberEditorInterval( 1 );
   textLabel5.SetNumberEditorUsesMouseWheel( false );
   textLabel5.SetHasCustomTextHoverColor( false );
   textLabel5.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel5.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel6 = new VoltageLabel( "textLabel6", "textLabel6", this, "Curve" );
   AddComponent( textLabel6 );
   textLabel6.SetWantsMouseNotifications( false );
   textLabel6.SetPosition( 78, 192 );
   textLabel6.SetSize( 43, 19 );
   textLabel6.SetEditable( false, false );
   textLabel6.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel6.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel6.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel6.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel6.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel6.SetBorderSize( 1 );
   textLabel6.SetMultiLineEdit( false );
   textLabel6.SetIsNumberEditor( false );
   textLabel6.SetNumberEditorRange( 0, 100 );
   textLabel6.SetNumberEditorInterval( 1 );
   textLabel6.SetNumberEditorUsesMouseWheel( false );
   textLabel6.SetHasCustomTextHoverColor( false );
   textLabel6.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel6.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel7 = new VoltageLabel( "textLabel7", "textLabel7", this, "Uni" );
   AddComponent( textLabel7 );
   textLabel7.SetWantsMouseNotifications( false );
   textLabel7.SetPosition( 6, 272 );
   textLabel7.SetSize( 22, 17 );
   textLabel7.SetEditable( false, false );
   textLabel7.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel7.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel7.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel7.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel7.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel7.SetBorderSize( 1 );
   textLabel7.SetMultiLineEdit( false );
   textLabel7.SetIsNumberEditor( false );
   textLabel7.SetNumberEditorRange( 0, 100 );
   textLabel7.SetNumberEditorInterval( 1 );
   textLabel7.SetNumberEditorUsesMouseWheel( false );
   textLabel7.SetHasCustomTextHoverColor( false );
   textLabel7.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel7.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel8 = new VoltageLabel( "textLabel8", "textLabel8", this, "Bi" );
   AddComponent( textLabel8 );
   textLabel8.SetWantsMouseNotifications( false );
   textLabel8.SetPosition( 9, 313 );
   textLabel8.SetSize( 16, 19 );
   textLabel8.SetEditable( false, false );
   textLabel8.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel8.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel8.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel8.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel8.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel8.SetBorderSize( 1 );
   textLabel8.SetMultiLineEdit( false );
   textLabel8.SetIsNumberEditor( false );
   textLabel8.SetNumberEditorRange( 0, 100 );
   textLabel8.SetNumberEditorInterval( 1 );
   textLabel8.SetNumberEditorUsesMouseWheel( false );
   textLabel8.SetHasCustomTextHoverColor( false );
   textLabel8.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel8.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel9 = new VoltageLabel( "textLabel9", "textLabel9", this, "Gate In" );
   AddComponent( textLabel9 );
   textLabel9.SetWantsMouseNotifications( false );
   textLabel9.SetPosition( 1, 29 );
   textLabel9.SetSize( 51, 15 );
   textLabel9.SetEditable( false, false );
   textLabel9.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel9.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel9.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel9.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel9.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel9.SetBorderSize( 1 );
   textLabel9.SetMultiLineEdit( false );
   textLabel9.SetIsNumberEditor( false );
   textLabel9.SetNumberEditorRange( 0, 100 );
   textLabel9.SetNumberEditorInterval( 1 );
   textLabel9.SetNumberEditorUsesMouseWheel( false );
   textLabel9.SetHasCustomTextHoverColor( false );
   textLabel9.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel9.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel11 = new VoltageLabel( "textLabel11", "textLabel11", this, "Hold" );
   AddComponent( textLabel11 );
   textLabel11.SetWantsMouseNotifications( false );
   textLabel11.SetPosition( 57, 28 );
   textLabel11.SetSize( 29, 17 );
   textLabel11.SetEditable( false, false );
   textLabel11.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel11.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel11.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel11.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel11.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel11.SetBorderSize( 1 );
   textLabel11.SetMultiLineEdit( false );
   textLabel11.SetIsNumberEditor( false );
   textLabel11.SetNumberEditorRange( 0, 100 );
   textLabel11.SetNumberEditorInterval( 1 );
   textLabel11.SetNumberEditorUsesMouseWheel( false );
   textLabel11.SetHasCustomTextHoverColor( false );
   textLabel11.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel11.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel12 = new VoltageLabel( "textLabel12", "textLabel12", this, "Manual" );
   AddComponent( textLabel12 );
   textLabel12.SetWantsMouseNotifications( false );
   textLabel12.SetPosition( 95, 28 );
   textLabel12.SetSize( 49, 17 );
   textLabel12.SetEditable( false, false );
   textLabel12.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel12.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel12.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel12.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel12.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel12.SetBorderSize( 1 );
   textLabel12.SetMultiLineEdit( false );
   textLabel12.SetIsNumberEditor( false );
   textLabel12.SetNumberEditorRange( 0, 100 );
   textLabel12.SetNumberEditorInterval( 1 );
   textLabel12.SetNumberEditorUsesMouseWheel( false );
   textLabel12.SetHasCustomTextHoverColor( false );
   textLabel12.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel12.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel13 = new VoltageLabel( "textLabel13", "textLabel13", this, "Outputs" );
   AddComponent( textLabel13 );
   textLabel13.SetWantsMouseNotifications( false );
   textLabel13.SetPosition( 65, 271 );
   textLabel13.SetSize( 42, 19 );
   textLabel13.SetEditable( false, false );
   textLabel13.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel13.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel13.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel13.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel13.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel13.SetBorderSize( 1 );
   textLabel13.SetMultiLineEdit( false );
   textLabel13.SetIsNumberEditor( false );
   textLabel13.SetNumberEditorRange( 0, 100 );
   textLabel13.SetNumberEditorInterval( 1 );
   textLabel13.SetNumberEditorUsesMouseWheel( false );
   textLabel13.SetHasCustomTextHoverColor( false );
   textLabel13.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel13.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel14 = new VoltageLabel( "textLabel14", "textLabel14", this, "CV In" );
   AddComponent( textLabel14 );
   textLabel14.SetWantsMouseNotifications( false );
   textLabel14.SetPosition( 55, 125 );
   textLabel14.SetSize( 33, 20 );
   textLabel14.SetEditable( false, false );
   textLabel14.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel14.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel14.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel14.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel14.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel14.SetBorderSize( 1 );
   textLabel14.SetMultiLineEdit( false );
   textLabel14.SetIsNumberEditor( false );
   textLabel14.SetNumberEditorRange( 0, 100 );
   textLabel14.SetNumberEditorInterval( 1 );
   textLabel14.SetNumberEditorUsesMouseWheel( false );
   textLabel14.SetHasCustomTextHoverColor( false );
   textLabel14.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel14.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel15 = new VoltageLabel( "textLabel15", "textLabel15", this, "Dome Music Technologies" );
   AddComponent( textLabel15 );
   textLabel15.SetWantsMouseNotifications( false );
   textLabel15.SetPosition( 18, 342 );
   textLabel15.SetSize( 108, 18 );
   textLabel15.SetEditable( false, false );
   textLabel15.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel15.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel15.SetColor( new Color( 2, 0, 133, 255 ) );
   textLabel15.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel15.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel15.SetBorderSize( 1 );
   textLabel15.SetMultiLineEdit( false );
   textLabel15.SetIsNumberEditor( false );
   textLabel15.SetNumberEditorRange( 0, 100 );
   textLabel15.SetNumberEditorInterval( 1 );
   textLabel15.SetNumberEditorUsesMouseWheel( false );
   textLabel15.SetHasCustomTextHoverColor( false );
   textLabel15.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel15.SetFont( "<Sans-Serif>", 10, false, false );

   outputSquare = new VoltageAudioJack( "State Output", "Square Output", this, JackType.JackType_AudioOutput );
   AddComponent( outputSquare );
   outputSquare.SetWantsMouseNotifications( false );
   outputSquare.SetPosition( 74, 290 );
   outputSquare.SetSize( 25, 25 );
   outputSquare.SetSkin( "Jack Round Sky Ring" );

   rateSwitch = new VoltageSwitch( "Time Factor", "Rate Switch", this, 0 );
   AddComponent( rateSwitch );
   rateSwitch.SetWantsMouseNotifications( false );
   rateSwitch.SetPosition( 52, 169 );
   rateSwitch.SetSize( 39, 15 );
   rateSwitch.SetSkin( "3-State Slide Horizontal" );

   textLabel18 = new VoltageLabel( "textLabel18", "textLabel18", this, "Slow" );
   AddComponent( textLabel18 );
   textLabel18.SetWantsMouseNotifications( false );
   textLabel18.SetPosition( 17, 169 );
   textLabel18.SetSize( 39, 15 );
   textLabel18.SetEditable( false, false );
   textLabel18.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel18.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel18.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel18.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel18.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel18.SetBorderSize( 1 );
   textLabel18.SetMultiLineEdit( false );
   textLabel18.SetIsNumberEditor( false );
   textLabel18.SetNumberEditorRange( 0, 100 );
   textLabel18.SetNumberEditorInterval( 1 );
   textLabel18.SetNumberEditorUsesMouseWheel( false );
   textLabel18.SetHasCustomTextHoverColor( false );
   textLabel18.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel18.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel19 = new VoltageLabel( "textLabel19", "textLabel19", this, "Fast" );
   AddComponent( textLabel19 );
   textLabel19.SetWantsMouseNotifications( false );
   textLabel19.SetPosition( 52, 154 );
   textLabel19.SetSize( 37, 17 );
   textLabel19.SetEditable( false, false );
   textLabel19.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel19.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel19.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel19.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel19.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel19.SetBorderSize( 1 );
   textLabel19.SetMultiLineEdit( false );
   textLabel19.SetIsNumberEditor( false );
   textLabel19.SetNumberEditorRange( 0, 100 );
   textLabel19.SetNumberEditorInterval( 1 );
   textLabel19.SetNumberEditorUsesMouseWheel( false );
   textLabel19.SetHasCustomTextHoverColor( false );
   textLabel19.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel19.SetFont( "<Sans-Serif>", 12, false, false );

   textLabel20 = new VoltageLabel( "textLabel20", "textLabel20", this, "Audio" );
   AddComponent( textLabel20 );
   textLabel20.SetWantsMouseNotifications( false );
   textLabel20.SetPosition( 92, 169 );
   textLabel20.SetSize( 32, 15 );
   textLabel20.SetEditable( false, false );
   textLabel20.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel20.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel20.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel20.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel20.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel20.SetBorderSize( 1 );
   textLabel20.SetMultiLineEdit( false );
   textLabel20.SetIsNumberEditor( false );
   textLabel20.SetNumberEditorRange( 0, 100 );
   textLabel20.SetNumberEditorInterval( 1 );
   textLabel20.SetNumberEditorUsesMouseWheel( false );
   textLabel20.SetHasCustomTextHoverColor( false );
   textLabel20.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel20.SetFont( "<Sans-Serif>", 12, false, false );

   curve1 = new VoltageCurve( "curve1", "curve1", this );
   AddComponent( curve1 );
   curve1.SetWantsMouseNotifications( false );
   curve1.SetPosition( 111, 317 );
   curve1.SetSize( 14, 16 );
   curve1.SetRange( (float)0.0, (float)1.0 );
   curve1.SetStartValue( (float)0.0 );
   curve1.SetEndValue( (float)1.0 );
   curve1.SetControlPoint1( (float)0.06, (float)0.85 );
   curve1.SetControlPoint2( (float)0.20, (float)0.20 );
   curve1.SetCurveThickness( (float)1.5 );
   curve1.SetBorderSize( (float)1.0 );
   curve1.SetHasRoundedCorners( true );
   curve1.SetCurveType( VoltageCurve.CurveType.Quadratic );
   curve1.SetControlPoint1EditType( VoltageCurve.ControlPt1EditType.BothXAndYEditable );
   curve1.SetBackgroundColor( new Color( 20, 140, 184, 0), VoltageCurve.MouseState.ALL_Mouse_States );
   curve1.SetCurveColor( new Color( 255, 255, 255, 255), VoltageCurve.MouseState.ALL_Mouse_States );
   curve1.SetBorderColor( new Color( 0, 0, 0, 0), VoltageCurve.MouseState.ALL_Mouse_States );
   curve1.SetDottedLineColor( new Color( 0, 0, 0, 0), VoltageCurve.MouseState.ALL_Mouse_States );
   curve1.SetEditable( false );
   curve1.SetHorizontal( true );

   outputRamp = new VoltageAudioJack( "Ramp Output", "Ramp Output", this, JackType.JackType_AudioOutput );
   AddComponent( outputRamp );
   outputRamp.SetWantsMouseNotifications( false );
   outputRamp.SetPosition( 37, 290 );
   outputRamp.SetSize( 25, 25 );
   outputRamp.SetSkin( "Jack Round Sky Ring" );

   riseLED = new VoltageLED( "Rise LED", "Rise LED", this );
   AddComponent( riseLED );
   riseLED.SetWantsMouseNotifications( false );
   riseLED.SetPosition( 66, 100 );
   riseLED.SetSize( 12, 12 );
   riseLED.SetSkin( "Green" );

   fallLED = new VoltageLED( "Fall LED", "Fall LED", this );
   AddComponent( fallLED );
   fallLED.SetWantsMouseNotifications( false );
   fallLED.SetPosition( 66, 218 );
   fallLED.SetSize( 12, 12 );
   fallLED.SetSkin( "Green" );

   gateLED = new VoltageLED( "Gate LED", "Gate LED", this );
   AddComponent( gateLED );
   gateLED.SetWantsMouseNotifications( false );
   gateLED.SetPosition( 87, 53 );
   gateLED.SetSize( 12, 12 );
   gateLED.SetSkin( "Red" );

   gateThresholdSwitch = new VoltageSwitch( "Gate Voltage", "Gate Voltage", this, 0 );
   AddComponent( gateThresholdSwitch );
   gateThresholdSwitch.SetWantsMouseNotifications( false );
   gateThresholdSwitch.SetPosition( 31, 48 );
   gateThresholdSwitch.SetSize( 20, 20 );
   gateThresholdSwitch.SetSkin( "2-State Bar Red" );

   textLabel21 = new VoltageLabel( "textLabel21", "textLabel21", this, "0V" );
   AddComponent( textLabel21 );
   textLabel21.SetWantsMouseNotifications( false );
   textLabel21.SetPosition( 31, 67 );
   textLabel21.SetSize( 20, 9 );
   textLabel21.SetEditable( false, false );
   textLabel21.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel21.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel21.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel21.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel21.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel21.SetBorderSize( 1 );
   textLabel21.SetMultiLineEdit( false );
   textLabel21.SetIsNumberEditor( false );
   textLabel21.SetNumberEditorRange( 0, 100 );
   textLabel21.SetNumberEditorInterval( 1 );
   textLabel21.SetNumberEditorUsesMouseWheel( false );
   textLabel21.SetHasCustomTextHoverColor( false );
   textLabel21.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel21.SetFont( "Verdana", 8, false, false );

   textLabel22 = new VoltageLabel( "textLabel22", "textLabel22", this, "2.5V" );
   AddComponent( textLabel22 );
   textLabel22.SetWantsMouseNotifications( false );
   textLabel22.SetPosition( 31, 40 );
   textLabel22.SetSize( 22, 13 );
   textLabel22.SetEditable( false, false );
   textLabel22.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel22.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel22.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel22.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel22.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel22.SetBorderSize( 1 );
   textLabel22.SetMultiLineEdit( false );
   textLabel22.SetIsNumberEditor( false );
   textLabel22.SetNumberEditorRange( 0, 100 );
   textLabel22.SetNumberEditorInterval( 1 );
   textLabel22.SetNumberEditorUsesMouseWheel( false );
   textLabel22.SetHasCustomTextHoverColor( false );
   textLabel22.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel22.SetFont( "Verdana", 8, false, false );
}



//-------------------------------------------------------------------------------
//  public void Initialize()

//  Initialize will get called shortly after your module's constructor runs. You can use it to
//  do any initialization that the auto-generated code doesn't handle.
//-------------------------------------------------------------------------------
@Override
public void Initialize()
{
   //[user-Initialize]   Add your own initialization code here

   outputSocket.SetValue(0.0);
   outputSquare.SetValue(0.0);
   outputRamp.SetValue(0.0);

   currentState = State.REST;
   previousDisplayState = State.REST;
   attackPeak = 5.0;
   currentValue = 0.0;
   gateOn = false;
   previousGateLEDon = false;

   SetPolarity();
   SetTimeBaseMultiplier();
   ReadGateThresholdSwitch();
   CalculateAttackTime();
   CalculateDecayTime();
   CalculateAttackCurve();
   CalculateDecayCurve();
   
   StartGuiUpdateTimer();

   //[/user-Initialize]
}


//-------------------------------------------------------------------------------
//  public void Destroy()

//  Destroy will get called just before your module gets deleted. You can use it to perform any
//  cleanup that's not handled automatically by Java.
//-------------------------------------------------------------------------------
@Override
public void Destroy()
{
   super.Destroy();
   //[user-Destroy]   Add your own module-getting-deleted code here



   //[/user-Destroy]
}


//-------------------------------------------------------------------------------
//  public boolean Notify( VoltageComponent component, ModuleNotifications notification, double doubleValue, long longValue, int x, int y, Object object )

//  Notify will get called when various events occur - control values changing, timers firing, etc.
//-------------------------------------------------------------------------------
@Override
public boolean Notify( VoltageComponent component, ModuleNotifications notification, double doubleValue, long longValue, int x, int y, Object object )
{
   //[user-Notify]   Add your own notification handling code between this line and the notify-close comment
   State currentLEDstate;
   boolean currentGateOnLED;

   switch( notification )
   {
      case Knob_Changed:   // doubleValue is the new VoltageKnob value
      {
      
         if (component == riseTimeKnob)
         {
            smoothRiseTime.SetValue(doubleValue);
         }
         else if (component == fallTimeKnob)
         {
            smoothFallTime.SetValue(doubleValue);
         }
         else if (component == riseCurveKnob)
         {
            smoothRiseCurve.SetValue(doubleValue);
         }
         else if (component == fallCurveKnob)
         {
            smoothFallCurve.SetValue(doubleValue);
         }         
         
      }
      break;
   
      case Slider_Changed:   // doubleValue is the new slider value
      {
      }
      break;
   
      case Button_Changed:   // doubleValue is the new button/toggle button value
      {
      }
      break;
   
      case Switch_Changed:   // doubleValue is the new switch value
      {
         // Only check for change in Rate Selector or Polarity as Gate Hold is checked every sample
         if (component == rateSwitch)
         {
            SetTimeBaseMultiplier();
         }
         else if (component == polaritySwitch)
         {
            SetPolarity();
         }
         else if (component == gateThresholdSwitch)
         {
            ReadGateThresholdSwitch();
         }
          

      }
      break;
   
      case Jack_Connected:   // longValue is the new cable ID
      {
         if (component == gateInSocket)
         {
            gateInConnected = true;
         }
         else if (component == riseTimeCV)
         {
            riseTimeCVConnected = true;
         }
         else if (component == riseCurveCV)
         {
            riseCurveCVConnected = true;
         }
         else if (component == fallTimeCV)
         {
            fallTimeCVConnected = true;
         }
         else if (component == fallCurveCV)
         {
            fallCurveCVConnected = true;
         }
         else if (component == outputSocket)
         {
            outputConnected = true;
         }
         else if (component == outputSquare)
         {
            squareOutputConnected = true;
         }
         else if (component == outputRamp)
         {
            rampOutputConnected = true;
         }
         
      }
      break;
   
      case Jack_Disconnected:   // All cables have been disconnected from this jack
      {
         if (component == gateInSocket)
         {
            gateInConnected = false;
         }
         else if (component == riseTimeCV)
         {
            riseTimeCVConnected = false;
            currentRiseTimeCV = 0.0;
            previousRiseTimeCV = 0.0;
            CalculateAttackTime();
         }
         else if (component == fallTimeCV)
         {
            fallTimeCVConnected = false;
            currentFallTimeCV = 0.0;
            previousFallTimeCV = 0.0;
            CalculateDecayTime();
         }
         else if (component == riseCurveCV)
         {
            riseCurveCVConnected = false;
            currentRiseCurveCV = 0.0;
            previousRiseCurveCV = 0.0;
            CalculateAttackCurve();
         }
         else if (component == fallCurveCV)
         {
            fallCurveCVConnected = false;
            currentFallCurveCV = 0.0;
            previousFallCurveCV = 0.0;
            CalculateDecayCurve();
         }
         else if (component == outputSocket)
         {
            outputConnected = false;
         }
         else if (component == outputSquare)
         {
            squareOutputConnected = false;
         }
         else if (component == outputRamp)
         {
            rampOutputConnected = false;
         }
         
      }
      break;
   
      case GUI_Update_Timer:   // Called every 50ms (by default) if turned on
      {
         currentLEDstate = currentState;
         currentGateOnLED = gateOn;
         
         if (currentLEDstate != previousDisplayState)
         {
            switch (previousDisplayState)
            {
               case REST:
               {
                  // Do nothing
               }
               break;
               
               case ATTACK:
               {
                  // Turn Rise LED off
                  riseLED.SetValue(0.0);
               }
               break;
               
               case DECAY:
               {
                  // Turn Fall LED off
                  fallLED.SetValue(0.0);
               }
               break;
               
            }

            switch (currentLEDstate)
            {
               case REST:
               {
                  // Do nothing
               }
               break;
               
               case ATTACK:
               {
                  // Turn Rise LED on
                  riseLED.SetValue(1.0);
               }
               break;
               
               case DECAY:
               {
                  // Turn Fall LED on
                  fallLED.SetValue(1.0);
               }
               break;
               
            }

            previousDisplayState = currentLEDstate;

         }
         
         
         if (currentGateOnLED != previousGateLEDon)
         {
            if (currentGateOnLED)            
            {
               gateLED.SetValue(1.0);
            }
            else
            {
               gateLED.SetValue(0.0);
            }
            
            previousGateLEDon = currentGateOnLED;
            
         }
      }
      break;
   
      case Object_MouseMove:   // called when mouse is over an object that receives mouse notifications. 'object' parameter is a VoltageMouseKeyFlags object.
      {
      }
      break;
   
      case Object_MouseLeave:  // called when mouse leaves an object that receives mouse notifications. 'object' parameter is a VoltageMouseKeyFlags object.
      {
      }
      break;
   
      case Object_LeftButtonDown:   // called when user left-clicks on an object that receives mouse notifications. 'object' parameter is a VoltageMouseKeyFlags object.
      {
      }
      break;
   
      case Object_LeftButtonUp:   // called when user releases left mouse button on an object that receives mouse notifications. 'object' parameter is a VoltageMouseKeyFlags object.
      {
      }
      break;
   
      case Object_RightButtonDown:   // called when user releases right mouse button on an object that receives mouse notifications. 'object' parameter is a VoltageMouseKeyFlags object.
      {
      }
      break;
   
      case Object_RightButtonUp:   // called when user right-clicks on an object that receives mouse notifications
      {
      }
      break;
   
      case Object_LeftButtonDoubleClick: // called when user left-button double-clicks on an object that receives mouse notifications
      {
      }
      break;
   
      // Less common notifications:
   
      case Named_Timer:   // object contains a String with the name of the timer that has fired
      {
      }
      break;
   
      case Canvas_Painting:   // About to paint canvas.  object is a java.awt.Rectangle with painting boundaries
      {
      }
      break;
   
      case Canvas_Painted:   // Canvas painting is complete
      {
      }
      break;
   
      case Control_DragStart:    // A user has started dragging on a control that has been marked as draggable
      {
      }
      break;
   
      case Control_DragOn:       // This control has been dragged over during a drag operation. object contains the dragged object
      {
      }
      break;
   
      case Control_DragOff:      // This control has been dragged over during a drag operation. object contains the dragged object
      {
      }
      break;
   
      case Control_DragEnd:      // A user has ended their drag on a control that has been marked as draggable
      {
      }
      break;
   
      case Label_Changed:        // The text of an editable text control has changed
      {
      }
      break;
   
      case SoundPlayback_Start:   // A sound has begun playback
      {
      }
      break;
   
      case SoundPlayback_End:     // A sound has ended playback
      {
      }
      break;
   
      case Scrollbar_Position:    // longValue is the new scrollbar position
      {
      }
      break;
   
      case PolyVoices_Changed:    // longValue is the new number of poly voices
      {
      }
      break;
   
      case File_Dropped:     // 'object' is a String containing the file path
      {
      }
      break;
   
      case Preset_Loading_Start:   // called when preset loading begins
      {
      }
      break;
   
      case Preset_Loading_Finish:  // called when preset loading finishes
      {
      }
      break;
   
      case Variation_Loading_Start:    // sent when a variation is about to load
      {
      }
      break;
   
      case Variation_Loading_Finish:   // sent when a variation has just finished loading
      {
      }
      break;
   
      case Tempo_Changed:     // doubleValue is the new tempo
      {
      }
      break;
   
      case Randomized:     // called when the module's controls get randomized
      {
      }
      break;
   
      case VariationListChanged:   // sent when a variation gets added, deleted, or renamed, or the variations list gets reordered
      {
      }
      break;
   
      case Key_Press:     // sent when module has keyboard focus and a key is pressed; object is a VoltageKeyPressInfo object
      {
      }
      break;
   
      case Reset:    // sent when the module has been reset to default settings
      {
      }
      break;
   
      case Keyboard_NoteOn:   // sent when a note has been pressed on a VoltageKeyboard object. longValue is the note value ( 0-127 )
      {
      }
      break;
   
      case Keyboard_NoteOff:   // sent when a note has been released on a VoltageKeyboard object. longValue is the note value ( 0-127 )
      {
      }
      break;
   
      case Curve_Changed:   // sent when user has edited a curve's value. 'object' will be a VoltageCurve.CurveChangeNotification object.
      {
      }
      break;
   }



   return false;
   //[/user-Notify]
}


//-------------------------------------------------------------------------------
//  public void ProcessSample()

//  ProcessSample is called once per sample. Usually it's where you read
//  from input jacks, process audio, and write it to your output jacks.
//  Since ProcesssSample gets called 48,000 times per second, offload CPU-intensive operations
//  to other threads when possible and avoid calling native functions.
//-------------------------------------------------------------------------------
@Override
public void ProcessSample()
{
   //[user-ProcessSample]   Add your own process-sampling code here

   boolean processChange;
   double reflectionDiff;

   // Always need to know if gate is on or off - wired OR
   gateOn = (gateInSocket.GetValue() > gateThresholdValue)  || // Above threshold
            (gateButton.GetValue() > 0.0) ||                   // Button Pressed = '1'
            (gateContSwitch.GetValue() > 0.0);                 // Continuous == '1'
               
   // Check for changes in knob positions and CV inputs
   // Initially, check all knobs and CVs every iteration.
   // If sockets are disconnected, CVs are unchanged and
   // knobs are stationary, then don't recalculate time constants.
   // Further increases in efficiency are still available
   // by checking only the two Rise parameters during ATTACK,
   // only the two Fall parameters during DECAY, and only Fall time
   // during REST. However, this might lead to undefined behaviour.
   // For initial release this 'check for changes' half-way house
   // should be sufficient in terms of streamlining the time spent
   // within ProcessSample.
      
   // Check for Rise Time value changes
   processChange = false;
   currentRiseTimeKnob = smoothRiseTime.GetSmoothValue();
   if (currentRiseTimeKnob != previousRiseTimeKnob)
   {
      processChange = true;
      previousRiseTimeKnob = currentRiseTimeKnob;
   }
   if (riseTimeCVConnected)
   {
      currentRiseTimeCV = riseTimeCV.GetValue();
      if (currentRiseTimeCV != previousRiseTimeCV)
      {
         processChange = true;
         previousRiseTimeCV = currentRiseTimeCV;
      }
   }
   if (processChange)
   {
      CalculateAttackTime();
   }

   // Check for Fall Time value changes
   processChange = false;
   currentFallTimeKnob = smoothFallTime.GetSmoothValue();
   if (currentFallTimeKnob != previousFallTimeKnob)
   {
      processChange = true;
      previousFallTimeKnob = currentFallTimeKnob;
   }
   if (fallTimeCVConnected)
   {
      currentFallTimeCV = fallTimeCV.GetValue();
      if (currentFallTimeCV != previousFallTimeCV)
      {
         processChange = true;
         previousFallTimeCV = currentFallTimeCV;
      }
   }
   if (processChange)
   {
      CalculateDecayTime();
   }

   // Check for Rise Curve value changes
   processChange = false;
   currentRiseCurveKnob = smoothRiseCurve.GetSmoothValue();
   if (currentRiseCurveKnob != previousRiseCurveKnob)
   {
      processChange = true;
      previousRiseCurveKnob = currentRiseCurveKnob;
   }
   if (riseCurveCVConnected)
   {
      currentRiseCurveCV = riseCurveCV.GetValue();
      if (currentRiseCurveCV != previousRiseCurveCV)
      {
         processChange = true;
         previousRiseCurveCV = currentRiseCurveCV;
      }
   }
   if (processChange)
   {
      CalculateAttackCurve();
   }

   // Check for Fall Curve value changes
   processChange = false;
   currentFallCurveKnob = smoothFallCurve.GetSmoothValue();
   if (currentFallCurveKnob != previousFallCurveKnob)
   {
      processChange = true;
      previousFallCurveKnob = currentFallCurveKnob;
   }
   if (fallCurveCVConnected)
   {
      currentFallCurveCV = fallCurveCV.GetValue();
      if (currentFallCurveCV != previousFallCurveCV)
      {
         processChange = true;
         previousFallCurveCV = currentFallCurveCV;
      }
   }
   if (processChange)
   {
      CalculateDecayCurve();
   }

   // Perform processing based on current state
   switch (currentState)
   {
      case REST:
      {
         // Return to 0.0 volts at Decay rate
         currentValue *= decayTimeFactor;
         outputSocket.SetValue(currentValue);
         outputSquare.SetValue(0.0);
         outputRamp.SetValue(currentValue);
            
         // Check for state transition
         if (gateOn)
         {
            // Switch to ATTACK state
            currentState = State.ATTACK;               
         }
      }
      break;
      
      case ATTACK:
      {
         if (gateOn)
         {
            // Calculate next capacitor value
            currentValue = attackTarget - ((attackTarget - currentValue) * attackTimeFactor);
                              
            // Check against attackPeak and switch to DECAY state if over
            if (currentValue > attackPeak)
            {
               // 'Reflect' voltage about attackPeak when switching state
               //
               reflectionDiff = (currentValue - attackPeak);
               currentValue = attackPeak - reflectionDiff;
               outputSquare.SetValue(decayPeak);
               currentState = State.DECAY;
               // To clamp to +5V, replace with commented-out code below.
               // currentValue = attackPeak;
               // currentState = State.DECAY;                  
            }
            else
            {
               outputSquare.SetValue(attackPeak);
            }
               
            outputSocket.SetValue(currentValue);
            if (currentPolarity == Polarity.UNIPOLAR)
            {
               outputRamp.SetValue(attackPeak - currentValue);
            }
            else
            {
               outputRamp.SetValue(-currentValue);
            }
            
         }
         else
         {
            outputSquare.SetValue(0.0);
            currentState = State.REST;
         }
      }
      break;
      
      case DECAY:
      {
         if (gateOn)
         {         
            // Calculate next capacitor value
            currentValue = decayTarget - ((decayTarget - currentValue) * decayTimeFactor);
               
            // Check against decayPeak and switch to DECAY state if over
            if (currentValue < decayPeak)
            {
               // 'Reflect' voltage about decayPeak when switching state
               //
               reflectionDiff = (currentValue - decayPeak);
               currentValue = decayPeak - reflectionDiff;
               currentState = State.ATTACK;
               // To clamp to -5V, replace with commented-out code below.
               // currentValue = decayPeak;
               // currentState = State.ATTACK;
            }
               
            outputSocket.SetValue(currentValue);
            outputSquare.SetValue(decayPeak);
            outputRamp.SetValue(currentValue);
               
         }
         else
         {
            currentState = State.REST;
         }
      }
      break;
      
   }  // End of switch (currentState)
      
   //[/user-ProcessSample]
}


//-------------------------------------------------------------------------------
//  public String GetTooltipText( VoltageComponent component )

//  Gets called when a tooltip is about to display for a control. Override it if
//  you want to change what the tooltip displays - if you want a knob to work in logarithmic fashion,
//  for instance, you can translate the knob's current value to a log-based string and display it here.
//-------------------------------------------------------------------------------
@Override
public String GetTooltipText( VoltageComponent component )
{
   //[user-GetTooltipText]   Add your own code here



   return super.GetTooltipText( component );
   //[/user-GetTooltipText]
}


//-------------------------------------------------------------------------------
//  public void EditComponentValue( VoltageComponent component, double newValue, String newText )

//  Gets called after a user clicks on a tooltip and types in a new value for a control. Override this if
//  you've changed the default tooltip display (translating a linear value to logarithmic, for instance)
//  in GetTooltipText().
//-------------------------------------------------------------------------------
@Override
public void EditComponentValue( VoltageComponent component, double newValue, String newText )
{
   //[user-EditComponentValue]   Add your own code here



   //[/user-EditComponentValue]
   super.EditComponentValue( component, newValue, newText );
}


//-------------------------------------------------------------------------------
//  public void OnUndoRedo( String undoType, double newValue, Object optionalObject )

//  If you've created custom undo events via calls to CreateUndoEvent, you'll need to
//  process them in this function when they get triggered by undo/redo actions.
//-------------------------------------------------------------------------------
@Override
public void OnUndoRedo( String undoType, double newValue, Object optionalObject )
{
   //[user-OnUndoRedo]   Add your own code here



   //[/user-OnUndoRedo]
}


//-------------------------------------------------------------------------------
//  public byte[] GetStateInformation()

//  Gets called when the module's state gets saved, typically when the user saves a preset with
//  this module in it. Voltage Modular will automatically save the states of knobs, sliders, etc.,
//  but if you have any custom state information you need to save, return it from this function.
//-------------------------------------------------------------------------------
@Override
public byte[] GetStateInformation()
{
   //[user-GetStateInformation]   Add your own code here



   return null;
   //[/user-GetStateInformation]
}


//-------------------------------------------------------------------------------
//  public void SetStateInformation(byte[] stateInfo)

//  Gets called when this module's state is getting restored, typically when a user opens a preset with
//  this module in it. The stateInfo parameter will contain whatever custom data you stored in GetStateInformation().
//-------------------------------------------------------------------------------
@Override
public void SetStateInformation(byte[] stateInfo)
{
   //[user-SetStateInformation]   Add your own code here



   //[/user-SetStateInformation]
}


//-------------------------------------------------------------------------------
//  public byte[] GetStateInformationForVariations()

//  Gets called when a user saves a variation with this module in it.
//  Voltage Modular will automatically save the states of knobs, sliders, etc.,
//  but if you have any custom state information you need to save, return it from this function.
//-------------------------------------------------------------------------------
@Override
public byte[] GetStateInformationForVariations()
{
   //[user-GetStateInformationForVariations]   Add your own code here



   return GetStateInformation();
   //[/user-GetStateInformationForVariations]
}


//-------------------------------------------------------------------------------
//  public void SetStateInformationForVariations(byte[] stateInfo)

//  Gets called when a user loads a variation with this module in it.
//  The stateInfo parameter will contain whatever custom data you stored in GetStateInformationForVariations().
//-------------------------------------------------------------------------------
@Override
public void SetStateInformationForVariations(byte[] stateInfo)
{
   //[user-SetStateInformationForVariations]   Add your own code here
   SetStateInformation(stateInfo);



   //[/user-SetStateInformationForVariations]
}


// Auto-generated variables
private VoltageLabel textLabel22;
private VoltageLabel textLabel21;
private VoltageSwitch gateThresholdSwitch;
private VoltageLED gateLED;
private VoltageLED fallLED;
private VoltageLED riseLED;
private VoltageAudioJack outputRamp;
private VoltageCurve curve1;
private VoltageLabel textLabel20;
private VoltageLabel textLabel19;
private VoltageLabel textLabel18;
private VoltageSwitch rateSwitch;
private VoltageAudioJack outputSquare;
private VoltageLabel textLabel15;
private VoltageLabel textLabel14;
private VoltageLabel textLabel13;
private VoltageLabel textLabel12;
private VoltageLabel textLabel11;
private VoltageLabel textLabel9;
private VoltageLabel textLabel8;
private VoltageLabel textLabel7;
private VoltageLabel textLabel6;
private VoltageLabel textLabel5;
private VoltageLabel textLabel4;
private VoltageLabel textLabel3;
private VoltageLabel textLabel2;
private VoltageLabel textLabel1;
private VoltageAudioJack outputSocket;
private VoltageSwitch polaritySwitch;
private VoltageAudioJack fallCurveCV;
private VoltageAudioJack fallTimeCV;
private VoltageAudioJack riseCurveCV;
private VoltageAudioJack riseTimeCV;
private VoltageKnob fallCurveKnob;
private VoltageKnob fallTimeKnob;
private VoltageKnob riseCurveKnob;
private VoltageKnob riseTimeKnob;
private VoltageButton gateButton;
private VoltageSwitch gateContSwitch;
private VoltageAudioJack gateInSocket;


//[user-code-and-variables]    Add your own variables and functions here

private enum State
{
   REST,       // Gate off - 'Release' phase, target = 0V
   ATTACK,     // Gate on, rising, target = attackTarget, threshold = attackPeak
   DECAY       // Gate on, falling, target = decayTarget, threshold = decayPeak
}

private enum Range
{
   SLOW,       // Time base multiplier = x1.00 seconds
   FAST,       // Time base multiplier = x0.10 seconds
   AUDIO       // Time base multiplier = x0.01 seconds
}

private enum Polarity
{
   UNIPOLAR,   //  0V to 5V output swing
   BIPOLAR     // -5V to 5V output swing
}

private State currentState;               // ATTACK / DECAY / REST
private Range currentRange;               // SLOW / FAST / AUDIO
private Polarity currentPolarity;         // UNIPOLAR / BIPOLAR

private double currentValue;              // Curve output voltage / Capacitor voltage

private double gateThresholdValue;        // Gate input threshold 0.0 or 2.5 V

private double timeBaseMultiplier;        // Slow / Fast / Audio ranges
private double attackTimeFactor;          // Exponential rise factor
private double decayTimeFactor;           // Exponential fall factor

private double attackPeak;                // +5V always
private double decayPeak;                 // 0V for unipolar, -5V for bipolar

private double attackTarget;              // Attack peak + overshoot
private double decayTarget;               // Decay peak - overshoot

private double attackOvershoot;           // Attack overshoot (curve shape)
private double decayOvershoot;            // Decay overshoot (curve shape)

private boolean gateOn;                   // Wired-OR of gate sources
private boolean previousGateLEDon;        // Previous displayed value

private State previousDisplayState;

// Input socket connection flags
private boolean gateInConnected;          // Gate socket connected
private boolean riseTimeCVConnected;      // Rise Time CV connected
private boolean riseCurveCVConnected;     // Rise Curve CV connected
private boolean fallTimeCVConnected;      // Fall Time CV connected
private boolean fallCurveCVConnected;     // Fall Curve CV connected

// Output socket connection flags
private boolean outputConnected;          // Curved output connected
private boolean squareOutputConnected;    // Square output connected
private boolean rampOutputConnected;      // Ramp output connected

// Knob and input smoothing and change detection for improved efficiency
private SmoothValue smoothRiseTime = new SmoothValue();
private double currentRiseTimeKnob;       // Current value return from SmoothValue
private double previousRiseTimeKnob;      // Previous value to check if changes need processed

private SmoothValue smoothFallTime = new SmoothValue();
private double currentFallTimeKnob;       // Current value return from SmoothValue
private double previousFallTimeKnob;      // Previous value to check if changes need processed

private SmoothValue smoothRiseCurve = new SmoothValue();
private double currentRiseCurveKnob;      // Current value return from SmoothValue
private double previousRiseCurveKnob;     // Previous value to check if changes need processed

private SmoothValue smoothFallCurve = new SmoothValue();
private double currentFallCurveKnob;      // Current value return from SmoothValue
private double previousFallCurveKnob;     // Previous value to check if changes need processed

private double currentRiseTimeCV;         // Current value direct from socket
private double previousRiseTimeCV;        // Previous value to check if changes need processed

private double currentFallTimeCV;         // Current value direct from socket
private double previousFallTimeCV;        // Previous value to check if changes need processed

private double currentRiseCurveCV;        // Current value direct from socket
private double previousRiseCurveCV;       // Previous value to check if changes need processed

private double currentFallCurveCV;        // Current value direct from socket
private double previousFallCurveCV;       // Previous value to check if changes need processed


// Private functions

private void SetPolarity ()
{
   int switchPos;
   
   switchPos = (int) round (polaritySwitch.GetValue());
   
   switch (switchPos)
   {
      case 0:
      {
         currentPolarity = Polarity.BIPOLAR;
      }
      break;
      
      case 1:
      {
         currentPolarity = Polarity.UNIPOLAR;
      }
      break;
      
   }  // End switch
   
   // Only decay curve should be affected, but keep for future-proofing.
   CalculateAttackCurve();
   CalculateDecayCurve();
   
}

private void SetTimeBaseMultiplier ()
{
   int switchPos;
   
   switchPos = (int) round(rateSwitch.GetValue());
   
   // All values for timeBaseMultiplier are negative for use in exp function
   
   switch (switchPos)
   {
      case 0:
      {
         currentRange = Range.SLOW;
         timeBaseMultiplier = -1.0 / Values.SampleRate;      // 1x base rate
      }
      break;
      
      case 1:
      {
         currentRange = Range.FAST;
         timeBaseMultiplier = -10.0 / Values.SampleRate;     // 10x base rate
      }
      break;
      
      case 2:
      {
         currentRange = Range.AUDIO;
         timeBaseMultiplier = -131.24 / Values.SampleRate;   // 131.24x base rate to match CA osc pitch
      }
      break;
      
   }
   
   CalculateAttackTime();
   CalculateDecayTime();
      
}

private void CalculateAttackTime ()
{
   double timePeriod;   // Base time period (knob * time base multiplier
   double temp;
   double voltsPerOctaveMultiplier;
   
   // Get base period / freq as set by front panel knob
   
   temp = timeBaseMultiplier / currentRiseTimeKnob;  // Basic RC time period
   
   // Modify base period by V/Oct CV input
   
   voltsPerOctaveMultiplier = pow (2.0, currentRiseTimeCV);  // Shorten period with increasing CV
   
   temp *= voltsPerOctaveMultiplier;
   
   attackTimeFactor = exp (temp);
   
}

private void CalculateDecayTime ()
{
   double timePeriod;   // Base time period (knob * time base multiplier
   double temp;
   double voltsPerOctaveMultiplier;
   
   // Get base period / freq as set by front panel knob
   
   temp = timeBaseMultiplier / currentFallTimeKnob;  // Basic RC time period
   
   // Modify base period by V/Oct CV input
   
   voltsPerOctaveMultiplier = pow (2.0, currentFallTimeCV);  // Shorten period with increasing CV
   
   temp *= voltsPerOctaveMultiplier;
   
   decayTimeFactor = exp (temp);
   
}

private void CalculateAttackCurve ()
{
   double clampedValue;
   double linearOvershoot;
   
   clampedValue = currentRiseCurveKnob;
   clampedValue += currentRiseCurveCV;
   
   if (clampedValue > 10.0) clampedValue = 10.0;
   if (clampedValue <  0.0) clampedValue =  0.0;
   
   linearOvershoot = (10.0 - clampedValue) / 10.0;       // 1.0 to 0.0 linear
   attackOvershoot = linearOvershoot * linearOvershoot;  // 1.0 to 0.0 exponential
   attackOvershoot *= 2.909883535;                       // 2.909883535 to 0.0 unipolar
   
   // attackPeak will always be +5V in current version
   
   if (currentPolarity == Polarity.BIPOLAR)
   {
      attackOvershoot *= 2.0; // 5.81976706 to 0.0 bipolar
   }
   
   attackTarget = attackPeak + attackOvershoot;
   
}

private void CalculateDecayCurve ()
{
   double clampedValue;
   double linearOvershoot;
   
   clampedValue = currentFallCurveKnob;
   clampedValue += currentFallCurveCV;
   
   if (clampedValue > 10.0) clampedValue = 10.0;
   if (clampedValue <  0.0) clampedValue =  0.0;
   
   linearOvershoot = (10.0 - clampedValue) / 10.0;       // 1.0 to 0.0 linear
   decayOvershoot = linearOvershoot * linearOvershoot;   // 1.0 to 0.0 exponential
   decayOvershoot *= 2.909883535;                        // 2.909883535 to 0.0 unipolar
   
   // decayPeak (and decayTarget change with setting of Polarity switch)
   
   if (currentPolarity == Polarity.UNIPOLAR)
   {
      decayPeak = 0.0;
   }
   else
   {
      decayPeak = -5.0;
      decayOvershoot *= 2.0;  // 5.81976706 to 0.0 bipolar
   }  
   
   decayTarget = decayPeak - decayOvershoot;
   
}

private void ReadGateThresholdSwitch ()
{
   if (gateThresholdSwitch.GetValue() > 0.0)
   {
      gateThresholdValue = 2.5;
   }
   else
   {
      gateThresholdValue = 0.0;
   }
}

//[/user-code-and-variables]
}

 