package com.domemusictechnologies.midipolypressure;


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 javax.sound.midi.ShortMessage;
import java.util.ArrayList;
import javax.sound.midi.InvalidMidiDataException;

//[/user-imports]


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

public MidiPolyPressure( long moduleID, VoltageObjects voltageObjects )
{
   super( moduleID, voltageObjects, "Poly Pressure Encoder", ModuleType.ModuleType_MIDI, 1.0 );

   InitializeControls();


   canBeBypassed = false;
   SetSkin( "12da8c14a3944c2cb633a1dc6c2062d9" );
}

void InitializeControls()
{

   textLabel1 = new VoltageLabel( "textLabel1", "textLabel1", this, "Poly Pressure Encoder" );
   AddComponent( textLabel1 );
   textLabel1.SetWantsMouseNotifications( false );
   textLabel1.SetPosition( 3, 0 );
   textLabel1.SetSize( 67, 44 );
   textLabel1.SetEditable( false, false );
   textLabel1.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel1.SetJustificationFlags( VoltageLabel.Justification.Top );
   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( true );
   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, false, false );

   textLabel2 = new VoltageLabel( "textLabel2", "textLabel2", this, "Dome Music Technologies" );
   AddComponent( textLabel2 );
   textLabel2.SetWantsMouseNotifications( false );
   textLabel2.SetPosition( 8, 342 );
   textLabel2.SetSize( 56, 18 );
   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( true );
   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( "Verdana", 8, false, false );

   midiInputJack = new VoltageMidiJack( "MIDI Input", "MIDI Input", this, JackType.JackType_MidiInput );
   AddComponent( midiInputJack );
   midiInputJack.SetWantsMouseNotifications( false );
   midiInputJack.SetPosition( 8, 110 );
   midiInputJack.SetSize( 57, 57 );
   midiInputJack.SetSkin( "MIDI Jack" );

   polyPitchInputJack = new VoltagePolyJack( "Poly Pitch Input", "Poly Pitch Input", this, JackType.JackType_PolyInput );
   AddComponent( polyPitchInputJack );
   polyPitchInputJack.SetWantsMouseNotifications( false );
   polyPitchInputJack.SetPosition( 24, 65 );
   polyPitchInputJack.SetSize( 25, 25 );
   polyPitchInputJack.SetSkin( "Poly Jack Straight" );

   midiOutputJack = new VoltageMidiJack( "MIDI Output", "MIDI Output", this, JackType.JackType_MidiOutput );
   AddComponent( midiOutputJack );
   midiOutputJack.SetWantsMouseNotifications( false );
   midiOutputJack.SetPosition( 8, 280 );
   midiOutputJack.SetSize( 57, 57 );
   midiOutputJack.SetSkin( "MIDI Jack" );

   polyPressureInput = new VoltagePolyJack( "Poly Pressure In", "Poly Pressure In", this, JackType.JackType_PolyInput );
   AddComponent( polyPressureInput );
   polyPressureInput.SetWantsMouseNotifications( false );
   polyPressureInput.SetPosition( 24, 186 );
   polyPressureInput.SetSize( 25, 25 );
   polyPressureInput.SetSkin( "Poly Jack Straight" );

   switchDataRate = new VoltageSwitch( "MIDI Data Rate", "MIDI Data Rate", this, 1 );
   AddComponent( switchDataRate );
   switchDataRate.SetWantsMouseNotifications( false );
   switchDataRate.SetPosition( 16, 232 );
   switchDataRate.SetSize( 39, 15 );
   switchDataRate.SetSkin( "3-State Slide Horizontal" );

   textLabel3 = new VoltageLabel( "textLabel3", "textLabel3", this, "Pitch In" );
   AddComponent( textLabel3 );
   textLabel3.SetWantsMouseNotifications( false );
   textLabel3.SetPosition( 1, 50 );
   textLabel3.SetSize( 71, 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( "Verdana", 12, false, false );

   textLabel4 = new VoltageLabel( "textLabel4", "textLabel4", this, "MIDI In" );
   AddComponent( textLabel4 );
   textLabel4.SetWantsMouseNotifications( false );
   textLabel4.SetPosition( 0, 96 );
   textLabel4.SetSize( 71, 14 );
   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( "Verdana", 12, false, false );

   textLabel5 = new VoltageLabel( "textLabel5", "textLabel5", this, "Pressure In" );
   AddComponent( textLabel5 );
   textLabel5.SetWantsMouseNotifications( false );
   textLabel5.SetPosition( 1, 171 );
   textLabel5.SetSize( 70, 14 );
   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( "Verdana", 12, false, false );

   textLabel6 = new VoltageLabel( "textLabel6", "textLabel6", this, "MIDI Rate" );
   AddComponent( textLabel6 );
   textLabel6.SetWantsMouseNotifications( false );
   textLabel6.SetPosition( 0, 218 );
   textLabel6.SetSize( 71, 14 );
   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( "Verdana", 12, false, false );

   textLabel7 = new VoltageLabel( "textLabel7", "textLabel7", this, "C" );
   AddComponent( textLabel7 );
   textLabel7.SetWantsMouseNotifications( false );
   textLabel7.SetPosition( 16, 245 );
   textLabel7.SetSize( 14, 12 );
   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( "Verdana", 12, false, false );

   textLabel8 = new VoltageLabel( "textLabel8", "textLabel8", this, "F" );
   AddComponent( textLabel8 );
   textLabel8.SetWantsMouseNotifications( false );
   textLabel8.SetPosition( 28, 245 );
   textLabel8.SetSize( 14, 12 );
   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( "Verdana", 12, false, false );

   textLabel9 = new VoltageLabel( "textLabel9", "textLabel9", this, "S" );
   AddComponent( textLabel9 );
   textLabel9.SetWantsMouseNotifications( false );
   textLabel9.SetPosition( 40, 245 );
   textLabel9.SetSize( 14, 12 );
   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( "Verdana", 12, false, false );

   textLabel10 = new VoltageLabel( "textLabel10", "textLabel10", this, "MIDI Out" );
   AddComponent( textLabel10 );
   textLabel10.SetWantsMouseNotifications( false );
   textLabel10.SetPosition( 0, 265 );
   textLabel10.SetSize( 71, 14 );
   textLabel10.SetEditable( false, false );
   textLabel10.SetJustificationFlags( VoltageLabel.Justification.HorizCentered );
   textLabel10.SetJustificationFlags( VoltageLabel.Justification.VertCentered );
   textLabel10.SetColor( new Color( 255, 255, 255, 255 ) );
   textLabel10.SetBkColor( new Color( 65, 65, 65, 0 ) );
   textLabel10.SetBorderColor( new Color( 0, 0, 0, 0 ) );
   textLabel10.SetBorderSize( 1 );
   textLabel10.SetMultiLineEdit( false );
   textLabel10.SetIsNumberEditor( false );
   textLabel10.SetNumberEditorRange( 0, 100 );
   textLabel10.SetNumberEditorInterval( 1 );
   textLabel10.SetNumberEditorUsesMouseWheel( false );
   textLabel10.SetHasCustomTextHoverColor( false );
   textLabel10.SetTextHoverColor( new Color( 0, 0, 0, 255 ) );
   textLabel10.SetFont( "Verdana", 12, 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

   currentMIDIChannel = 0;
   
   SetPolyphony(GetNumberOfPolyVoices());
   CheckConnections();
   ReadMIDIRateSwitch(switchDataRate.GetValue());

   //[/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
   switch( notification )
   {
      case Knob_Changed:   // doubleValue is the new VoltageKnob value
      {
      }
      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
      {
         if (component == switchDataRate)
         {
            ReadMIDIRateSwitch(doubleValue);
         }
      }
      break;
   
      case Jack_Connected:   // longValue is the new cable ID
      {
         CheckConnections();
      }
      break;
   
      case Jack_Disconnected:   // All cables have been disconnected from this jack
      {
         CheckConnections();
      }
      break;
   
      case GUI_Update_Timer:   // Called every 50ms (by default) if turned on
      {
      }
      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
      {
         SetPolyphony((int)longValue);
      }
      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

   ArrayList<ShortMessage> events; 
   int tempPressure;
   float tempNoteVoltage;
   int i;
   
   // Pass through all MIDI messages except for CHANNEL_PRESSURE

   // Process any pending MIDI input stream messages
   if (midiInConnected)
   {
      // Read from module's MIDI In jack
      events = midiInputJack.GetMessages();
   }
   else
   {
      // Normalled to IO Panel "FROM HOST"
      events = GetIOPanelMIDIMessages();
   }
   
   // events will be non-null if there are
   // MIDI events to process
   if (events != null)
   {
      int numEvents = events.size();
        
      for (int ix = 0; ix < numEvents; ix++)
      {
         ShortMessage event = events.get(ix);
         
         int inputChannel = event.getChannel();
         int inputCommand = event.getCommand();
         
         currentMIDIChannel = inputChannel;
         
         switch (inputCommand)
         {
         
            case ShortMessage.CHANNEL_PRESSURE:
            {
               // Remove from input stream
            }
            break;
            
            case ShortMessage.POLY_PRESSURE:
            {
               // Remove from input stream
            }
            break;
            
            default:
            {
               // Pass through all other messages, unaffected
               int inputData1   = event.getData1();
               int inputData2   = event.getData2();
            
               ShortMessage passThroughEvent = new ShortMessage();
               
               try
               {
                  passThroughEvent.setMessage(inputCommand, inputChannel, inputData1, inputData2);
               }
               catch (InvalidMidiDataException e)
               {
                  // Do nothing for time being
               }            
               
               midiOutputJack.AddMessage(passThroughEvent);
            
            }
            break;
            
         }
      }
      
   }
   
   // Now, process analogue poly voltage inputs to detect changes
   
   midiTimeoutCount--;
   
   if (midiTimeoutCount <= 0)
   {
      // Timeout period has elapsed. Reset timeout counter.
      midiTimeoutCount = midiTimeoutPeriod;
      
      // Reset change detection flags for this iteration      
      for (i=0; i < currentPolyphony; i++)
      {
         sendMessage[i] = false;
      }
   
      // Read poly pitch inputs and assign to MIDI note numbers.      
      if (polyPitchInConnected)
      {
         // Read from Poly Pitch Input Jack
         for (i=0; i < currentPolyphony; i++)
         {
            tempNoteVoltage = (float)polyPitchInputJack.GetPolyValue(i);
            if (tempNoteVoltage != previousNoteV[i])
            {
               previousNoteV[i] = tempNoteVoltage;
               channelNote[i] = VoltsToMIDINote(tempNoteVoltage);
               sendMessage[i] = true;  // Flag change detected
            }
         }
      }
      else
      {
         // Normalled to IO Panel when jack disconnected
         for (i=0; i < currentPolyphony; i++)
         {
            tempNoteVoltage = (float)GetIOPanelPolyValue(IOPanelPolyValues.IOPanel_PolyPitch, i);
            if (tempNoteVoltage != previousNoteV[i])
            {
               previousNoteV[i] = tempNoteVoltage;
               channelNote[i] = VoltsToMIDINote(tempNoteVoltage);
               sendMessage[i] = true;  // Flag change detected
            }
         }
      }
      
      // Read Poly Pressure CV inputs and detect new MIDI value
      for (i=0; i < currentPolyphony; i++)
      {
         tempPressure = VoltsToPressure((float)polyPressureInput.GetPolyValue(i));
         if (channelPressure[i] != tempPressure)
         {
            channelPressure[i] = tempPressure;
            sendMessage[i] = true;  // Flag change detected
         }
      }
      
      // Output MIDI Poly Pressure message if change detected on note number or pressure value.
      for (i=0; i < currentPolyphony; i++)
      {
         if (sendMessage[i])
         {
            // Change detected - add MIDI PolyPressure event to output stream
            OutputPolyPressureEvent(channelNote[i], channelPressure[i]);
         }
      }
               
   }  // End of MIDI timeout check

   //[/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 textLabel10;
private VoltageLabel textLabel9;
private VoltageLabel textLabel8;
private VoltageLabel textLabel7;
private VoltageLabel textLabel6;
private VoltageLabel textLabel5;
private VoltageLabel textLabel4;
private VoltageLabel textLabel3;
private VoltageSwitch switchDataRate;
private VoltagePolyJack polyPressureInput;
private VoltageMidiJack midiOutputJack;
private VoltagePolyJack polyPitchInputJack;
private VoltageMidiJack midiInputJack;
private VoltageLabel textLabel2;
private VoltageLabel textLabel1;


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

// Constants

private final int MAX_POLY_VOICES = GetMaxNumberOfPolyVoices();

private final float SEMITONES_PER_OCTAVE = 12.0f;
private final float C2_VOLTAGE_OFFSET = 36.5f;  // 36 seimtones + 0.5 for rounding to int
private final float PRESSURE_SCALER = 25.4f;    // 0V = 0, 5V = 127
private final float PRESSURE_OFFSET = 0.5f;     // Added for rounding to int

private final int MIDI_NOTE_LOW = 0;
private final int MIDI_NOTE_HIGH = 127;
private final int MIDI_PRESSURE_LOW = 0;
private final int MIDI_PRESSURE_HIGH = 127;
private final int MIDI_TIMEOUT_SLOW = 480;      // 10ms
private final int MIDI_TIMEOUT_FAST = 48;       // 1ms
private final int MIDI_TIMEOUT_CONTINUOUS = 1;  // Every cycle (1/48ms)


// Variables

private int currentMIDIChannel;
private int currentPolyphony;
private int midiTimeoutPeriod;
private int midiTimeoutCount;

private int[] channelNote     =  new int[MAX_POLY_VOICES];
private int[] channelPressure =  new int[MAX_POLY_VOICES];
private float[] previousNoteV =  new float [MAX_POLY_VOICES];
private boolean[] sendMessage =  new boolean [MAX_POLY_VOICES];

// Input connected flags

private boolean polyPitchInConnected;  
private boolean midiInConnected;
private boolean polyPressureInConnected;  
private boolean midiOutConnected;

void CheckConnections()
{
   polyPitchInConnected    = polyPitchInputJack.IsConnected();
   polyPressureInConnected = polyPressureInput.IsConnected();
   midiInConnected         = midiInputJack.IsConnected();
   midiOutConnected        = midiOutputJack.IsConnected();
   
}

void SetPolyphony(int polyphony)
{
   currentPolyphony = polyphony;
   
   for (int i = 0; i < currentPolyphony; i++)
   {
      channelNote[i] = 0;
      channelPressure[i] = 0;
      previousNoteV[i] = -10.0f;
   }
}

void ReadMIDIRateSwitch(double midiRate)
{
   if (midiRate > 1.5)
   {
      midiTimeoutPeriod = MIDI_TIMEOUT_SLOW;
   }
   else if (midiRate > 0.5)
   {
      midiTimeoutPeriod = MIDI_TIMEOUT_FAST;
   }
   else
   {
      midiTimeoutPeriod = MIDI_TIMEOUT_CONTINUOUS;
   }
   
   // Reset counter to poll inputs on next cycle
   midiTimeoutCount = 1;
   
}


private int VoltsToMIDINote (float volts)
{
   int noteNumber;
   
   noteNumber = (int) (volts * SEMITONES_PER_OCTAVE + C2_VOLTAGE_OFFSET);
   
   if (noteNumber < MIDI_NOTE_LOW) return MIDI_NOTE_LOW;
   if (noteNumber > MIDI_NOTE_HIGH) return MIDI_NOTE_HIGH;
   
   return noteNumber;
}

private int VoltsToPressure (float volts)
{
   int pressure;
   
   pressure = (int) (volts * PRESSURE_SCALER + PRESSURE_OFFSET);
   
   if (pressure < MIDI_PRESSURE_LOW) return MIDI_PRESSURE_LOW;
   if (pressure > MIDI_PRESSURE_HIGH) return MIDI_PRESSURE_HIGH;
   
   return pressure;
}

private void OutputPolyPressureEvent(int midiNote, int midiPressure)
{
   ShortMessage polyPressureEvent = new ShortMessage();
         
   try
   {
      polyPressureEvent.setMessage(ShortMessage.POLY_PRESSURE, currentMIDIChannel, midiNote, midiPressure);
   }
   catch (InvalidMidiDataException e)
   {
      // Do nothing for time being
   }
               
   midiOutputJack.AddMessage(polyPressureEvent);   
   
}

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

 