1 /* 2 * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.sound.sampled; 27 28 /** 29 * A {@code FloatControl} object provides control over a range of floating-point 30 * values. Float controls are often represented in graphical user interfaces by 31 * continuously adjustable objects such as sliders or rotary knobs. Concrete 32 * subclasses of {@code FloatControl} implement controls, such as gain and pan, 33 * that affect a line's audio signal in some way that an application can 34 * manipulate. The {@link FloatControl.Type} inner class provides static 35 * instances of types that are used to identify some common kinds of float 36 * control. 37 * <p> 38 * The {@code FloatControl} abstract class provides methods to set and get the 39 * control's current floating-point value. Other methods obtain the possible 40 * range of values and the control's resolution (the smallest increment between 41 * returned values). Some float controls allow ramping to a new value over a 42 * specified period of time. {@code FloatControl} also includes methods that 43 * return string labels for the minimum, maximum, and midpoint positions of the 44 * control. 45 * 46 * @author David Rivas 47 * @author Kara Kytle 48 * @see Line#getControls 49 * @see Line#isControlSupported 50 * @since 1.3 51 */ 52 public abstract class FloatControl extends Control { 53 54 /** 55 * The minimum supported value. 56 */ 57 private final float minimum; 58 59 /** 60 * The maximum supported value. 61 */ 62 private final float maximum; 63 64 /** 65 * The control's precision. 66 */ 67 private final float precision; 68 69 /** 70 * The smallest time increment in which a value change can be effected 71 * during a value shift, in microseconds. 72 */ 73 private final int updatePeriod; 74 75 /** 76 * A label for the units in which the control values are expressed, such as 77 * "dB" for decibels. 78 */ 79 private final String units; 80 81 /** 82 * A label for the minimum value, such as "Left". 83 */ 84 private final String minLabel; 85 86 /** 87 * A label for the maximum value, such as "Right". 88 */ 89 private final String maxLabel; 90 91 /** 92 * A label for the mid-point value, such as "Center". 93 */ 94 private final String midLabel; 95 96 /** 97 * The current value. 98 */ 99 private float value; 100 101 /** 102 * Constructs a new float control object with the given parameters. 103 * 104 * @param type the kind of control represented by this float control object 105 * @param minimum the smallest value permitted for the control 106 * @param maximum the largest value permitted for the control 107 * @param precision the resolution or granularity of the control. This is 108 * the size of the increment between discrete valid values. 109 * @param updatePeriod the smallest time interval, in microseconds, over 110 * which the control can change from one discrete value to the next 111 * during a {@link #shift(float,float,int) shift} 112 * @param initialValue the value that the control starts with when 113 * constructed 114 * @param units the label for the units in which the control's values are 115 * expressed, such as "dB" or "frames per second" 116 * @param minLabel the label for the minimum value, such as "Left" or "Off" 117 * @param midLabel the label for the midpoint value, such as "Center" or 118 * "Default" 119 * @param maxLabel the label for the maximum value, such as "Right" or 120 * "Full" 121 * @throws IllegalArgumentException if {@code minimum} is greater than 122 * {@code maximum} or {@code initialValue} does not fall within the 123 * allowable range 124 */ 125 protected FloatControl(Type type, float minimum, float maximum, 126 float precision, int updatePeriod, float initialValue, 127 String units, String minLabel, String midLabel, String maxLabel) { 128 129 super(type); 130 131 if (minimum > maximum) { 132 throw new IllegalArgumentException("Minimum value " + minimum 133 + " exceeds maximum value " + maximum + "."); 134 } 135 if (initialValue < minimum) { 136 throw new IllegalArgumentException("Initial value " + initialValue 137 + " smaller than allowable minimum value " + minimum + "."); 138 } 139 if (initialValue > maximum) { 140 throw new IllegalArgumentException("Initial value " + initialValue 141 + " exceeds allowable maximum value " + maximum + "."); 142 } 143 144 145 this.minimum = minimum; 146 this.maximum = maximum; 147 148 this.precision = precision; 149 this.updatePeriod = updatePeriod; 150 this.value = initialValue; 151 152 this.units = units; 153 this.minLabel = ( (minLabel == null) ? "" : minLabel); 154 this.midLabel = ( (midLabel == null) ? "" : midLabel); 155 this.maxLabel = ( (maxLabel == null) ? "" : maxLabel); 156 } 157 158 /** 159 * Constructs a new float control object with the given parameters. The 160 * labels for the minimum, maximum, and mid-point values are set to 161 * zero-length strings. 162 * 163 * @param type the kind of control represented by this float control object 164 * @param minimum the smallest value permitted for the control 165 * @param maximum the largest value permitted for the control 166 * @param precision the resolution or granularity of the control. This is 167 * the size of the increment between discrete valid values. 168 * @param updatePeriod the smallest time interval, in microseconds, over 169 * which the control can change from one discrete value to the next 170 * during a {@link #shift(float,float,int) shift} 171 * @param initialValue the value that the control starts with when 172 * constructed 173 * @param units the label for the units in which the control's values are 174 * expressed, such as "dB" or "frames per second" 175 * @throws IllegalArgumentException if {@code minimum} is greater than 176 * {@code maximum} or {@code initialValue} does not fall within the 177 * allowable range 178 */ 179 protected FloatControl(Type type, float minimum, float maximum, 180 float precision, int updatePeriod, float initialValue, String units) { 181 this(type, minimum, maximum, precision, updatePeriod, 182 initialValue, units, "", "", ""); 183 } 184 185 /** 186 * Sets the current value for the control. The default implementation simply 187 * sets the value as indicated. If the value indicated is greater than the 188 * maximum value, or smaller than the minimum value, an 189 * {@code IllegalArgumentException} is thrown. Some controls require that 190 * their line be open before they can be affected by setting a value. 191 * 192 * @param newValue desired new value 193 * @throws IllegalArgumentException if the value indicated does not fall 194 * within the allowable range 195 */ 196 public void setValue(float newValue) { 197 198 if (newValue > maximum) { 199 throw new IllegalArgumentException("Requested value " + newValue + " exceeds allowable maximum value " + maximum + "."); 200 } 201 202 if (newValue < minimum) { 203 throw new IllegalArgumentException("Requested value " + newValue + " smaller than allowable minimum value " + minimum + "."); 204 } 205 206 value = newValue; 207 } 208 209 /** 210 * Obtains this control's current value. 211 * 212 * @return the current value 213 */ 214 public float getValue() { 215 return value; 216 } 217 218 /** 219 * Obtains the maximum value permitted. 220 * 221 * @return the maximum allowable value 222 */ 223 public float getMaximum() { 224 return maximum; 225 } 226 227 /** 228 * Obtains the minimum value permitted. 229 * 230 * @return the minimum allowable value 231 */ 232 public float getMinimum() { 233 return minimum; 234 } 235 236 /** 237 * Obtains the label for the units in which the control's values are 238 * expressed, such as "dB" or "frames per second." 239 * 240 * @return the units label, or a zero-length string if no label 241 */ 242 public String getUnits() { 243 return units; 244 } 245 246 /** 247 * Obtains the label for the minimum value, such as "Left" or "Off". 248 * 249 * @return the minimum value label, or a zero-length string if no label has 250 * been set 251 */ 252 public String getMinLabel() { 253 return minLabel; 254 } 255 256 /** 257 * Obtains the label for the mid-point value, such as "Center" or "Default". 258 * 259 * @return the mid-point value label, or a zero-length string if no label 260 * has been set 261 */ 262 public String getMidLabel() { 263 return midLabel; 264 } 265 266 /** 267 * Obtains the label for the maximum value, such as "Right" or "Full". 268 * 269 * @return the maximum value label, or a zero-length string if no label has 270 * been set 271 */ 272 public String getMaxLabel() { 273 return maxLabel; 274 } 275 276 /** 277 * Obtains the resolution or granularity of the control, in the units that 278 * the control measures. The precision is the size of the increment between 279 * discrete valid values for this control, over the set of supported 280 * floating-point values. 281 * 282 * @return the control's precision 283 */ 284 public float getPrecision() { 285 return precision; 286 } 287 288 /** 289 * Obtains the smallest time interval, in microseconds, over which the 290 * control's value can change during a shift. The update period is the 291 * inverse of the frequency with which the control updates its value during 292 * a shift. If the implementation does not support value shifting over time, 293 * it should set the control's value to the final value immediately and 294 * return -1 from this method. 295 * 296 * @return update period in microseconds, or -1 if shifting over time is 297 * unsupported 298 * @see #shift 299 */ 300 public int getUpdatePeriod() { 301 return updatePeriod; 302 } 303 304 /** 305 * Changes the control value from the initial value to the final value 306 * linearly over the specified time period, specified in microseconds. This 307 * method returns without blocking; it does not wait for the shift to 308 * complete. An implementation should complete the operation within the time 309 * specified. The default implementation simply changes the value to the 310 * final value immediately. 311 * 312 * @param from initial value at the beginning of the shift 313 * @param to final value after the shift 314 * @param microseconds maximum duration of the shift in microseconds 315 * @throws IllegalArgumentException if either {@code from} or {@code to} 316 * value does not fall within the allowable range 317 * @see #getUpdatePeriod 318 */ 319 public void shift(float from, float to, int microseconds) { 320 // test "from" value, "to" value will be tested by setValue() 321 if (from < minimum) { 322 throw new IllegalArgumentException("Requested value " + from 323 + " smaller than allowable minimum value " + minimum + "."); 324 } 325 if (from > maximum) { 326 throw new IllegalArgumentException("Requested value " + from 327 + " exceeds allowable maximum value " + maximum + "."); 328 } 329 setValue(to); 330 } 331 332 /** 333 * Provides a string representation of the control. 334 * 335 * @return a string description 336 */ 337 @Override 338 public String toString() { 339 return new String(getType() + " with current value: " + getValue() + " " + units + 340 " (range: " + minimum + " - " + maximum + ")"); 341 } 342 343 /** 344 * An instance of the {@code FloatControl.Type} inner class identifies one 345 * kind of float control. Static instances are provided for the common 346 * types. 347 * 348 * @author Kara Kytle 349 * @since 1.3 350 */ 351 public static class Type extends Control.Type { 352 353 /** 354 * Represents a control for the overall gain on a line. 355 * <p> 356 * Gain is a quantity in decibels (dB) that is added to the intrinsic 357 * decibel level of the audio signal--that is, the level of the signal 358 * before it is altered by the gain control. A positive gain amplifies 359 * (boosts) the signal's volume, and a negative gain attenuates(cuts)it. 360 * The gain setting defaults to a value of 0.0 dB, meaning the signal's 361 * loudness is unaffected. Note that gain measures dB, not amplitude. 362 * The relationship between a gain in decibels and the corresponding 363 * linear amplitude multiplier is: 364 * 365 * <CENTER>{@code linearScalar = pow(10.0, gainDB/20.0)}</CENTER> 366 * <p> 367 * The {@code FloatControl} class has methods to impose a maximum and 368 * minimum allowable value for gain. However, because an audio signal 369 * might already be at a high amplitude, the maximum setting does not 370 * guarantee that the signal will be undistorted when the gain is 371 * applied to it (unless the maximum is zero or negative). To avoid 372 * numeric overflow from excessively large gain settings, a gain control 373 * can implement clipping, meaning that the signal's amplitude will be 374 * limited to the maximum value representable by its audio format, 375 * instead of wrapping around. 376 * <p> 377 * These comments apply to gain controls in general, not just master 378 * gain controls. A line can have more than one gain control. For 379 * example, a mixer (which is itself a line) might have a master gain 380 * control, an auxiliary return control, a reverb return control, and, 381 * on each of its source lines, an individual aux send and reverb send. 382 * 383 * @see #AUX_SEND 384 * @see #AUX_RETURN 385 * @see #REVERB_SEND 386 * @see #REVERB_RETURN 387 * @see #VOLUME 388 */ 389 public static final Type MASTER_GAIN = new Type("Master Gain"); 390 391 /** 392 * Represents a control for the auxiliary send gain on a line. 393 * 394 * @see #MASTER_GAIN 395 * @see #AUX_RETURN 396 */ 397 public static final Type AUX_SEND = new Type("AUX Send"); 398 399 /** 400 * Represents a control for the auxiliary return gain on a line. 401 * 402 * @see #MASTER_GAIN 403 * @see #AUX_SEND 404 */ 405 public static final Type AUX_RETURN = new Type("AUX Return"); 406 407 /** 408 * Represents a control for the pre-reverb gain on a line. This control 409 * may be used to affect how much of a line's signal is directed to a 410 * mixer's internal reverberation unit. 411 * 412 * @see #MASTER_GAIN 413 * @see #REVERB_RETURN 414 * @see EnumControl.Type#REVERB 415 */ 416 public static final Type REVERB_SEND = new Type("Reverb Send"); 417 418 /** 419 * Represents a control for the post-reverb gain on a line. This control 420 * may be used to control the relative amplitude of the signal returned 421 * from an internal reverberation unit. 422 * 423 * @see #MASTER_GAIN 424 * @see #REVERB_SEND 425 */ 426 public static final Type REVERB_RETURN = new Type("Reverb Return"); 427 428 /** 429 * Represents a control for the volume on a line. 430 */ 431 /* 432 * $$kk: 08.30.99: ISSUE: what units? linear or dB? 433 */ 434 public static final Type VOLUME = new Type("Volume"); 435 436 /** 437 * Represents a control for the relative pan (left-right positioning) of 438 * the signal. The signal may be mono; the pan setting affects how it is 439 * distributed by the mixer in a stereo mix. The valid range of values 440 * is -1.0 (left channel only) to 1.0 (right channel only). The default 441 * is 0.0 (centered). 442 * 443 * @see #BALANCE 444 */ 445 public static final Type PAN = new Type("Pan"); 446 447 /** 448 * Represents a control for the relative balance of a stereo signal 449 * between two stereo speakers. The valid range of values is -1.0 (left 450 * channel only) to 1.0 (right channel only). The default is 0.0 451 * (centered). 452 * 453 * @see #PAN 454 */ 455 public static final Type BALANCE = new Type("Balance"); 456 457 /** 458 * Represents a control that changes the sample rate of audio playback. 459 * The net effect of changing the sample rate depends on the 460 * relationship between the media's natural rate and the rate that is 461 * set via this control. The natural rate is the sample rate that is 462 * specified in the data line's {@code AudioFormat} object. For example, 463 * if the natural rate of the media is 11025 samples per second and the 464 * sample rate is set to 22050 samples per second, the media will play 465 * back at twice the normal speed. 466 * <p> 467 * Changing the sample rate with this control does not affect the data 468 * line's audio format. Also note that whenever you change a sound's 469 * sample rate, a change in the sound's pitch results. For example, 470 * doubling the sample rate has the effect of doubling the frequencies 471 * in the sound's spectrum, which raises the pitch by an octave. 472 */ 473 public static final Type SAMPLE_RATE = new Type("Sample Rate"); 474 475 /** 476 * Constructs a new float control type. 477 * 478 * @param name the name of the new float control type 479 */ 480 protected Type(final String name) { 481 super(name); 482 } 483 } 484 }