content: /*
   * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
   * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   */
  
  package lib.sound.sampled;
  
  /**
   * A <code>FloatControl</code> object provides control over a range of
   * floating-point values.  Float controls are often
   * represented in graphical user interfaces by continuously
   * adjustable objects such as sliders or rotary knobs.  Concrete subclasses
   * of <code>FloatControl</code> implement controls, such as gain and pan, that
   * affect a line's audio signal in some way that an application can manipulate.
   * The <code>{@link FloatControl.Type}</code>
   * inner class provides static instances of types that are used to
   * identify some common kinds of float control.
   * <p/>
   * The <code>FloatControl</code> abstract class provides methods to set and get
   * the control's current floating-point value.  Other methods obtain the possible
   * range of values and the control's resolution (the smallest increment between
   * returned values).  Some float controls allow ramping to a
   * new value over a specified period of time.  <code>FloatControl</code> also
   * includes methods that return string labels for the minimum, maximum, and midpoint
   * positions of the control.
   *
   * @author David Rivas
   * @author Kara Kytle
   * @see Line#getControls
   * @see Line#isControlSupported
   * @since 1.3
   */
  public abstract class FloatControl extends Control {
  
  
      // INSTANCE VARIABLES
  
  
      // FINAL VARIABLES
  
      /**
       * A label for the units in which the control values are expressed,
       * such as "dB" for decibels.
       */
      private final String units;
      /**
       * A label for the minimum value, such as "Left."
       */
      private final String minLabel;
      /**
       * A label for the maximum value, such as "Right."
       */
      private final String maxLabel;
      /**
       * A label for the mid-point value, such as "Center."
       */
      private final String midLabel;
      /**
       * The minimum supported value.
       */
      private float minimum;
      /**
       * The maximum supported value.
       */
      private float maximum;
      /**
       * The control's precision.
       */
      private float precision;
      /**
       * The smallest time increment in which a value change
       * can be effected during a value shift, in microseconds.
       */
      private int updatePeriod;
  
  
      // STATE VARIABLES
      /**
       * The current value.
       */
      private float value;
  
  
      // CONSTRUCTORS
  
  
      /**
       * Constructs a new float control object with the given parameters
       *
       * @param type         the kind of control represented by this float control object
       * @param minimum      the smallest value permitted for the control
       * @param maximum      the largest value permitted for the control
       * @param precision    the resolution or granularity of the control.
       *                     This is the size of the increment between discrete valid values.
       * @param updatePeriod the smallest time interval, in microseconds, over which the control
       *                     can change from one discrete value to the next during a {@link #shift(float, float, int) shift}
       * @param initialValue the value that the control starts with when constructed
       * @param units        the label for the units in which the control's values are expressed,
       *                     such as "dB" or "frames per second"
       * @param minLabel     the label for the minimum value, such as "Left" or "Off"
       * @param midLabel     the label for the midpoint value, such as "Center" or "Default"
       * @param maxLabel     the label for the maximum value, such as "Right" or "Full"
       * @throws IllegalArgumentException if {@code minimum} is greater
       *                                  than {@code maximum} or {@code initialValue} does not fall
       *                                  within the allowable range
       */
      protected FloatControl(Type type, float minimum, float maximum,
                             float precision, int updatePeriod, float initialValue,
                             String units, String minLabel, String midLabel, String maxLabel) {
  
          super(type);
  
          if (minimum > maximum) {
              throw new IllegalArgumentException("Minimum value " + minimum
                      + " exceeds maximum value " + maximum + ".");
          }
          if (initialValue < minimum) {
              throw new IllegalArgumentException("Initial value " + initialValue
                      + " smaller than allowable minimum value " + minimum + ".");
          }
          if (initialValue > maximum) {
              throw new IllegalArgumentException("Initial value " + initialValue
                      + " exceeds allowable maximum value " + maximum + ".");
          }
  
  
          this.minimum = minimum;
          this.maximum = maximum;
  
          this.precision = precision;
          this.updatePeriod = updatePeriod;
          this.value = initialValue;
  
          this.units = units;
          this.minLabel = ((minLabel == null) ? "" : minLabel);
          this.midLabel = ((midLabel == null) ? "" : midLabel);
          this.maxLabel = ((maxLabel == null) ? "" : maxLabel);
      }
  
  
      /**
       * Constructs a new float control object with the given parameters.
       * The labels for the minimum, maximum, and mid-point values are set
       * to zero-length strings.
       *
       * @param type         the kind of control represented by this float control object
       * @param minimum      the smallest value permitted for the control
       * @param maximum      the largest value permitted for the control
       * @param precision    the resolution or granularity of the control.
       *                     This is the size of the increment between discrete valid values.
       * @param updatePeriod the smallest time interval, in microseconds, over which the control
       *                     can change from one discrete value to the next during a {@link #shift(float, float, int) shift}
       * @param initialValue the value that the control starts with when constructed
       * @param units        the label for the units in which the control's values are expressed,
       *                     such as "dB" or "frames per second"
       * @throws IllegalArgumentException if {@code minimum} is greater
       *                                  than {@code maximum} or {@code initialValue} does not fall
       *                                  within the allowable range
       */
      protected FloatControl(Type type, float minimum, float maximum,
                             float precision, int updatePeriod, float initialValue, String units) {
          this(type, minimum, maximum, precision, updatePeriod,
                  initialValue, units, "", "", "");
      }
  
  
      // METHODS
  
      /**
       * Obtains this control's current value.
       *
       * @return the current value
       */
      public float getValue() {
          return value;
      }
  
      /**
       * Sets the current value for the control.  The default implementation
       * simply sets the value as indicated.  If the value indicated is greater
       * than the maximum value, or smaller than the minimum value, an
       * IllegalArgumentException is thrown.
       * Some controls require that their line be open before they can be affected
       * by setting a value.
       *
       * @param newValue desired new value
       * @throws IllegalArgumentException if the value indicated does not fall
       *                                  within the allowable range
       */
      public void setValue(float newValue) {
  
          if (newValue > maximum) {
              throw new IllegalArgumentException("Requested value " + newValue + " exceeds allowable maximum value " + maximum + ".");
          }
  
          if (newValue < minimum) {
              throw new IllegalArgumentException("Requested value " + newValue + " smaller than allowable minimum value " + minimum + ".");
          }
  
          value = newValue;
      }
  
      /**
       * Obtains the maximum value permitted.
       *
       * @return the maximum allowable value
       */
      public float getMaximum() {
          return maximum;
      }
  
  
      /**
       * Obtains the minimum value permitted.
       *
       * @return the minimum allowable value
       */
      public float getMinimum() {
          return minimum;
      }
  
  
      /**
       * Obtains the label for the units in which the control's values are expressed,
       * such as "dB" or "frames per second."
       *
       * @return the units label, or a zero-length string if no label
       */
      public String getUnits() {
          return units;
      }
  
  
      /**
       * Obtains the label for the minimum value, such as "Left" or "Off."
       *
       * @return the minimum value label, or a zero-length string if no label      * has been set
       */
      public String getMinLabel() {
          return minLabel;
      }
  
  
      /**
       * Obtains the label for the mid-point value, such as "Center" or "Default."
       *
       * @return the mid-point value label, or a zero-length string if no label    * has been set
       */
      public String getMidLabel() {
          return midLabel;
      }
  
  
      /**
       * Obtains the label for the maximum value, such as "Right" or "Full."
       *
       * @return the maximum value label, or a zero-length string if no label      * has been set
       */
      public String getMaxLabel() {
          return maxLabel;
      }
  
  
      /**
       * Obtains the resolution or granularity of the control, in the units
       * that the control measures.
       * The precision is the size of the increment between discrete valid values
       * for this control, over the set of supported floating-point values.
       *
       * @return the control's precision
       */
      public float getPrecision() {
          return precision;
      }
  
  
      /**
       * Obtains the smallest time interval, in microseconds, over which the control's value can
       * change during a shift.  The update period is the inverse of the frequency with which
       * the control updates its value during a shift.  If the implementation does not support value shifting over
       * time, it should set the control's value to the final value immediately
       * and return -1 from this method.
       *
       * @return update period in microseconds, or -1 if shifting over time is unsupported
       * @see #shift
       */
      public int getUpdatePeriod() {
          return updatePeriod;
      }
  
  
      /**
       * Changes the control value from the initial value to the final
       * value linearly over the specified time period, specified in microseconds.
       * This method returns without blocking; it does not wait for the shift
       * to complete.  An implementation should complete the operation within the time
       * specified.  The default implementation simply changes the value
       * to the final value immediately.
       *
       * @param from         initial value at the beginning of the shift
       * @param to           final value after the shift
       * @param microseconds maximum duration of the shift in microseconds
       * @throws IllegalArgumentException if either {@code from} or {@code to}
       *                                  value does not fall within the allowable range
       * @see #getUpdatePeriod
       */
      public void shift(float from, float to, int microseconds) {
          // test "from" value, "to" value will be tested by setValue()
          if (from < minimum) {
              throw new IllegalArgumentException("Requested value " + from
                      + " smaller than allowable minimum value " + minimum + ".");
          }
          if (from > maximum) {
              throw new IllegalArgumentException("Requested value " + from
                      + " exceeds allowable maximum value " + maximum + ".");
          }
          setValue(to);
      }
  
  
      // ABSTRACT METHOD IMPLEMENTATIONS: CONTROL
  
  
      /**
       * Provides a string representation of the control
       *
       * @return a string description
       */
      public String toString() {
          return new String(getType() + " with current value: " + getValue() + " " + units +
                  " (range: " + minimum + " - " + maximum + ")");
      }
  
  
      // INNER CLASSES
  
  
      /**
       * An instance of the <code>FloatControl.Type</code> inner class identifies one kind of
       * float control.  Static instances are provided for the
       * common types.
       *
       * @author Kara Kytle
       * @since 1.3
       */
      public static class Type extends Control.Type {
  
  
          // TYPE DEFINES
  
  
          // GAIN TYPES
  
          /**
           * Represents a control for the overall gain on a line.
           * <p/>
           * Gain is a quantity in decibels (dB) that is added to the intrinsic
           * decibel level of the audio signal--that is, the level of
           * the signal before it is altered by the gain control.  A positive
           * gain amplifies (boosts) the signal's volume, and a negative gain
           * attenuates (cuts) it.
           * The gain setting defaults to a value of 0.0 dB, meaning the signal's
           * loudness is unaffected.   Note that gain measures dB, not amplitude.
           * The relationship between a gain in decibels and the corresponding
           * linear amplitude multiplier is:
           * <p/>
           * <CENTER><CODE> linearScalar = pow(10.0, gainDB/20.0) </CODE></CENTER>
           * <p/>
           * The <code>FloatControl</code> class has methods to impose a maximum and
           * minimum allowable value for gain.  However, because an audio signal might
           * already be at a high amplitude, the maximum setting does not guarantee
           * that the signal will be undistorted when the gain is applied to it (unless
           * the maximum is zero or negative). To avoid numeric overflow from excessively
           * large gain settings, a gain control can implement
           * clipping, meaning that the signal's amplitude will be limited to the maximum
           * value representable by its audio format, instead of wrapping around.
           * <p/>
           * These comments apply to gain controls in general, not just master gain controls.
           * A line can have more than one gain control.  For example, a mixer (which is
           * itself a line) might have a master gain control, an auxiliary return control,
           * a reverb return control, and, on each of its source lines, an individual aux
           * send and reverb send.
           *
           * @see #AUX_SEND
           * @see #AUX_RETURN
           * @see #REVERB_SEND
           * @see #REVERB_RETURN
           * @see #VOLUME
           */
          public static final Type MASTER_GAIN = new Type("Master Gain");
  
          /**
           * Represents a control for the auxiliary send gain on a line.
           *
           * @see #MASTER_GAIN
           * @see #AUX_RETURN
           */
          public static final Type AUX_SEND = new Type("AUX Send");
  
          /**
           * Represents a control for the auxiliary return gain on a line.
           *
           * @see #MASTER_GAIN
           * @see #AUX_SEND
           */
          public static final Type AUX_RETURN = new Type("AUX Return");
  
          /**
           * Represents a control for the pre-reverb gain on a line.
           * This control may be used to affect how much
           * of a line's signal is directed to a mixer's internal reverberation unit.
           *
           * @see #MASTER_GAIN
           * @see #REVERB_RETURN
           * @see EnumControl.Type#REVERB
           */
          public static final Type REVERB_SEND = new Type("Reverb Send");
  
          /**
           * Represents a control for the post-reverb gain on a line.
           * This control may be used to control the relative amplitude
           * of the signal returned from an internal reverberation unit.
           *
           * @see #MASTER_GAIN
           * @see #REVERB_SEND
           */
          public static final Type REVERB_RETURN = new Type("Reverb Return");
  
  
          // VOLUME
  
          /**
           * Represents a control for the volume on a line.
           */
          /*
           * $$kk: 08.30.99: ISSUE: what units?  linear or dB?
           */
          public static final Type VOLUME = new Type("Volume");
  
  
          // PAN
  
          /**
           * Represents a control for the relative pan (left-right positioning)
           * of the signal.  The signal may be mono; the pan setting affects how
           * it is distributed by the mixer in a stereo mix.  The valid range of values is -1.0
           * (left channel only) to 1.0 (right channel
           * only).  The default is 0.0 (centered).
           *
           * @see #BALANCE
           */
          public static final Type PAN = new Type("Pan");
  
  
          // BALANCE
  
          /**
           * Represents a control for the relative balance of a stereo signal
           * between two stereo speakers.  The valid range of values is -1.0 (left channel only) to 1.0 (right channel
           * only).  The default is 0.0 (centered).
           *
           * @see #PAN
           */
          public static final Type BALANCE = new Type("Balance");
  
  
          // SAMPLE RATE
  
          /**
           * Represents a control that changes the sample rate of audio playback.  The net effect
           * of changing the sample rate depends on the relationship between
           * the media's natural rate and the rate that is set via this control.
           * The natural rate is the sample rate that is specified in the data line's
           * <code>AudioFormat</code> object.  For example, if the natural rate
           * of the media is 11025 samples per second and the sample rate is set
           * to 22050 samples per second, the media will play back at twice the
           * normal speed.
           * <p/>
           * Changing the sample rate with this control does not affect the data line's
           * audio format.  Also note that whenever you change a sound's sample rate, a
           * change in the sound's pitch results.  For example, doubling the sample
           * rate has the effect of doubling the frequencies in the sound's spectrum,
           * which raises the pitch by an octave.
           */
          public static final Type SAMPLE_RATE = new Type("Sample Rate");
  
  
          // CONSTRUCTOR
  
          /**
           * Constructs a new float control type.
           *
           * @param name the name of the new float control type
           */
          protected Type(String name) {
              super(name);
          }
  
      } // class Type
  
  } // class FloatControl
  