1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.audiofx; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.media.audiofx.AudioEffect; 23 import android.os.Bundle; 24 import android.util.Log; 25 26 import java.nio.ByteOrder; 27 import java.nio.ByteBuffer; 28 import java.util.StringTokenizer; 29 30 /** 31 * A sound generated within a room travels in many directions. The listener first hears the direct 32 * sound from the source itself. Later, he or she hears discrete echoes caused by sound bouncing off 33 * nearby walls, the ceiling and the floor. As sound waves arrive after undergoing more and more 34 * reflections, individual reflections become indistinguishable and the listener hears continuous 35 * reverberation that decays over time. 36 * Reverb is vital for modeling a listener's environment. It can be used in music applications 37 * to simulate music being played back in various environments, or in games to immerse the 38 * listener within the game's environment. 39 * The EnvironmentalReverb class allows an application to control each reverb engine property in a 40 * global reverb environment and is more suitable for games. For basic control, more suitable for 41 * music applications, it is recommended to use the 42 * {@link android.media.audiofx.PresetReverb} class. 43 * <p>An application creates a EnvironmentalReverb object to instantiate and control a reverb engine 44 * in the audio framework. 45 * <p>The methods, parameter types and units exposed by the EnvironmentalReverb implementation are 46 * directly mapping those defined by the OpenSL ES 1.0.1 Specification 47 * (http://www.khronos.org/opensles/) for the SLEnvironmentalReverbItf interface. 48 * Please refer to this specification for more details. 49 * <p>The EnvironmentalReverb is an output mix auxiliary effect and should be created on 50 * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect, 51 * they must be explicitely attached to it and a send level must be specified. Use the effect ID 52 * returned by getId() method to designate this particular effect when attaching it to the 53 * MediaPlayer or AudioTrack. 54 * <p>Creating a reverb on the output mix (audio session 0) requires permission 55 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} 56 * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling 57 * audio effects. 58 */ 59 60 public class EnvironmentalReverb extends AudioEffect { 61 62 private final static String TAG = "EnvironmentalReverb"; 63 64 // These constants must be synchronized with those in 65 // frameworks/base/include/media/EffectEnvironmentalReverbApi.h 66 67 /** 68 * Room level. Parameter ID for OnParameterChangeListener 69 */ 70 public static final int PARAM_ROOM_LEVEL = 0; 71 /** 72 * Room HF level. Parameter ID for OnParameterChangeListener 73 */ 74 public static final int PARAM_ROOM_HF_LEVEL = 1; 75 /** 76 * Decay time. Parameter ID for OnParameterChangeListener 77 */ 78 public static final int PARAM_DECAY_TIME = 2; 79 /** 80 * Decay HF ratio. Parameter ID for 81 * {@link android.media.audiofx.EnvironmentalReverb.OnParameterChangeListener} 82 */ 83 public static final int PARAM_DECAY_HF_RATIO = 3; 84 /** 85 * Early reflections level. Parameter ID for OnParameterChangeListener 86 */ 87 public static final int PARAM_REFLECTIONS_LEVEL = 4; 88 /** 89 * Early reflections delay. Parameter ID for OnParameterChangeListener 90 */ 91 public static final int PARAM_REFLECTIONS_DELAY = 5; 92 /** 93 * Reverb level. Parameter ID for OnParameterChangeListener 94 */ 95 public static final int PARAM_REVERB_LEVEL = 6; 96 /** 97 * Reverb delay. Parameter ID for OnParameterChangeListener 98 */ 99 public static final int PARAM_REVERB_DELAY = 7; 100 /** 101 * Diffusion. Parameter ID for OnParameterChangeListener 102 */ 103 public static final int PARAM_DIFFUSION = 8; 104 /** 105 * Density. Parameter ID for OnParameterChangeListener 106 */ 107 public static final int PARAM_DENSITY = 9; 108 109 // used by setProperties()/getProperties 110 private static final int PARAM_PROPERTIES = 10; 111 112 /** 113 * Registered listener for parameter changes 114 */ 115 private OnParameterChangeListener mParamListener = null; 116 117 /** 118 * Listener used internally to to receive raw parameter change event from AudioEffect super 119 * class 120 */ 121 private BaseParameterListener mBaseParamListener = null; 122 123 /** 124 * Lock for access to mParamListener 125 */ 126 private final Object mParamListenerLock = new Object(); 127 128 /** 129 * Class constructor. 130 * @param priority the priority level requested by the application for controlling the 131 * EnvironmentalReverb engine. As the same engine can be shared by several applications, this 132 * parameter indicates how much the requesting application needs control of effect parameters. 133 * The normal priority is 0, above normal is a positive number, below normal a negative number. 134 * @param audioSession system wide unique audio session identifier. If audioSession 135 * is not 0, the EnvironmentalReverb will be attached to the MediaPlayer or AudioTrack in the 136 * same audio session. Otherwise, the EnvironmentalReverb will apply to the output mix. 137 * As the EnvironmentalReverb is an auxiliary effect it is recommended to instantiate it on 138 * audio session 0 and to attach it to the MediaPLayer auxiliary output. 139 * 140 * @throws java.lang.IllegalArgumentException 141 * @throws java.lang.UnsupportedOperationException 142 * @throws java.lang.RuntimeException 143 */ 144 public EnvironmentalReverb(int priority, int audioSession) 145 throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { 146 super(EFFECT_TYPE_ENV_REVERB, EFFECT_TYPE_NULL, priority, audioSession); 147 } 148 149 /** 150 * Sets the master volume level of the environmental reverb effect. 151 * @param room room level in millibels. The valid range is [-9000, 0]. 152 * @throws IllegalStateException 153 * @throws IllegalArgumentException 154 * @throws UnsupportedOperationException 155 */ 156 public void setRoomLevel(short room) 157 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 158 byte[] param = shortToByteArray(room); 159 checkStatus(setParameter(PARAM_ROOM_LEVEL, param)); 160 } 161 162 /** 163 * Gets the master volume level of the environmental reverb effect. 164 * @return the room level in millibels. 165 * @throws IllegalStateException 166 * @throws IllegalArgumentException 167 * @throws UnsupportedOperationException 168 */ 169 public short getRoomLevel() 170 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 171 byte[] param = new byte[2]; 172 checkStatus(getParameter(PARAM_ROOM_LEVEL, param)); 173 return byteArrayToShort(param); 174 } 175 176 /** 177 * Sets the volume level at 5 kHz relative to the volume level at low frequencies of the 178 * overall reverb effect. 179 * <p>This controls a low-pass filter that will reduce the level of the high-frequency. 180 * @param roomHF high frequency attenuation level in millibels. The valid range is [-9000, 0]. 181 * @throws IllegalStateException 182 * @throws IllegalArgumentException 183 * @throws UnsupportedOperationException 184 */ 185 public void setRoomHFLevel(short roomHF) 186 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 187 byte[] param = shortToByteArray(roomHF); 188 checkStatus(setParameter(PARAM_ROOM_HF_LEVEL, param)); 189 } 190 191 /** 192 * Gets the room HF level. 193 * @return the room HF level in millibels. 194 * @throws IllegalStateException 195 * @throws IllegalArgumentException 196 * @throws UnsupportedOperationException 197 */ 198 public short getRoomHFLevel() 199 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 200 byte[] param = new byte[2]; 201 checkStatus(getParameter(PARAM_ROOM_HF_LEVEL, param)); 202 return byteArrayToShort(param); 203 } 204 205 /** 206 * Sets the time taken for the level of reverberation to decay by 60 dB. 207 * @param decayTime decay time in milliseconds. The valid range is [100, 20000]. 208 * @throws IllegalStateException 209 * @throws IllegalArgumentException 210 * @throws UnsupportedOperationException 211 */ 212 public void setDecayTime(int decayTime) 213 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 214 byte[] param = intToByteArray(decayTime); 215 checkStatus(setParameter(PARAM_DECAY_TIME, param)); 216 } 217 218 /** 219 * Gets the decay time. 220 * @return the decay time in milliseconds. 221 * @throws IllegalStateException 222 * @throws IllegalArgumentException 223 * @throws UnsupportedOperationException 224 */ 225 public int getDecayTime() 226 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 227 byte[] param = new byte[4]; 228 checkStatus(getParameter(PARAM_DECAY_TIME, param)); 229 return byteArrayToInt(param); 230 } 231 232 /** 233 * Sets the ratio of high frequency decay time (at 5 kHz) relative to the decay time at low 234 * frequencies. 235 * @param decayHFRatio high frequency decay ratio using a permille scale. The valid range is 236 * [100, 2000]. A ratio of 1000 indicates that all frequencies decay at the same rate. 237 * @throws IllegalStateException 238 * @throws IllegalArgumentException 239 * @throws UnsupportedOperationException 240 */ 241 public void setDecayHFRatio(short decayHFRatio) 242 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 243 byte[] param = shortToByteArray(decayHFRatio); 244 checkStatus(setParameter(PARAM_DECAY_HF_RATIO, param)); 245 } 246 247 /** 248 * Gets the ratio of high frequency decay time (at 5 kHz) relative to low frequencies. 249 * @return the decay HF ration. See {@link #setDecayHFRatio(short)} for units. 250 * @throws IllegalStateException 251 * @throws IllegalArgumentException 252 * @throws UnsupportedOperationException 253 */ 254 public short getDecayHFRatio() 255 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 256 byte[] param = new byte[2]; 257 checkStatus(getParameter(PARAM_DECAY_HF_RATIO, param)); 258 return byteArrayToShort(param); 259 } 260 261 /** 262 * Sets the volume level of the early reflections. 263 * <p>This level is combined with the overall room level 264 * (set using {@link #setRoomLevel(short)}). 265 * @param reflectionsLevel reflection level in millibels. The valid range is [-9000, 1000]. 266 * @throws IllegalStateException 267 * @throws IllegalArgumentException 268 * @throws UnsupportedOperationException 269 */ 270 public void setReflectionsLevel(short reflectionsLevel) 271 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 272 byte[] param = shortToByteArray(reflectionsLevel); 273 checkStatus(setParameter(PARAM_REFLECTIONS_LEVEL, param)); 274 } 275 276 /** 277 * Gets the volume level of the early reflections. 278 * @return the early reflections level in millibels. 279 * @throws IllegalStateException 280 * @throws IllegalArgumentException 281 * @throws UnsupportedOperationException 282 */ 283 public short getReflectionsLevel() 284 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 285 byte[] param = new byte[2]; 286 checkStatus(getParameter(PARAM_REFLECTIONS_LEVEL, param)); 287 return byteArrayToShort(param); 288 } 289 290 /** 291 * Sets the delay time for the early reflections. 292 * <p>This method sets the time between when the direct path is heard and when the first 293 * reflection is heard. 294 * @param reflectionsDelay reflections delay in milliseconds. The valid range is [0, 300]. 295 * @throws IllegalStateException 296 * @throws IllegalArgumentException 297 * @throws UnsupportedOperationException 298 */ 299 public void setReflectionsDelay(int reflectionsDelay) 300 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 301 byte[] param = intToByteArray(reflectionsDelay); 302 checkStatus(setParameter(PARAM_REFLECTIONS_DELAY, param)); 303 } 304 305 /** 306 * Gets the reflections delay. 307 * @return the early reflections delay in milliseconds. 308 * @throws IllegalStateException 309 * @throws IllegalArgumentException 310 * @throws UnsupportedOperationException 311 */ 312 public int getReflectionsDelay() 313 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 314 byte[] param = new byte[4]; 315 checkStatus(getParameter(PARAM_REFLECTIONS_DELAY, param)); 316 return byteArrayToInt(param); 317 } 318 319 /** 320 * Sets the volume level of the late reverberation. 321 * <p>This level is combined with the overall room level (set using {@link #setRoomLevel(short)}). 322 * @param reverbLevel reverb level in millibels. The valid range is [-9000, 2000]. 323 * @throws IllegalStateException 324 * @throws IllegalArgumentException 325 * @throws UnsupportedOperationException 326 */ 327 public void setReverbLevel(short reverbLevel) 328 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 329 byte[] param = shortToByteArray(reverbLevel); 330 checkStatus(setParameter(PARAM_REVERB_LEVEL, param)); 331 } 332 333 /** 334 * Gets the reverb level. 335 * @return the reverb level in millibels. 336 * @throws IllegalStateException 337 * @throws IllegalArgumentException 338 * @throws UnsupportedOperationException 339 */ 340 public short getReverbLevel() 341 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 342 byte[] param = new byte[2]; 343 checkStatus(getParameter(PARAM_REVERB_LEVEL, param)); 344 return byteArrayToShort(param); 345 } 346 347 /** 348 * Sets the time between the first reflection and the reverberation. 349 * @param reverbDelay reverb delay in milliseconds. The valid range is [0, 100]. 350 * @throws IllegalStateException 351 * @throws IllegalArgumentException 352 * @throws UnsupportedOperationException 353 */ 354 public void setReverbDelay(int reverbDelay) 355 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 356 byte[] param = intToByteArray(reverbDelay); 357 checkStatus(setParameter(PARAM_REVERB_DELAY, param)); 358 } 359 360 /** 361 * Gets the reverb delay. 362 * @return the reverb delay in milliseconds. 363 * @throws IllegalStateException 364 * @throws IllegalArgumentException 365 * @throws UnsupportedOperationException 366 */ 367 public int getReverbDelay() 368 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 369 byte[] param = new byte[4]; 370 checkStatus(getParameter(PARAM_REVERB_DELAY, param)); 371 return byteArrayToInt(param); 372 } 373 374 /** 375 * Sets the echo density in the late reverberation decay. 376 * <p>The scale should approximately map linearly to the perceived change in reverberation. 377 * @param diffusion diffusion specified using a permille scale. The diffusion valid range is 378 * [0, 1000]. A value of 1000 o/oo indicates a smooth reverberation decay. 379 * Values below this level give a more <i>grainy</i> character. 380 * @throws IllegalStateException 381 * @throws IllegalArgumentException 382 * @throws UnsupportedOperationException 383 */ 384 public void setDiffusion(short diffusion) 385 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 386 byte[] param = shortToByteArray(diffusion); 387 checkStatus(setParameter(PARAM_DIFFUSION, param)); 388 } 389 390 /** 391 * Gets diffusion level. 392 * @return the diffusion level. See {@link #setDiffusion(short)} for units. 393 * @throws IllegalStateException 394 * @throws IllegalArgumentException 395 * @throws UnsupportedOperationException 396 */ 397 public short getDiffusion() 398 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 399 byte[] param = new byte[2]; 400 checkStatus(getParameter(PARAM_DIFFUSION, param)); 401 return byteArrayToShort(param); 402 } 403 404 405 /** 406 * Controls the modal density of the late reverberation decay. 407 * <p> The scale should approximately map linearly to the perceived change in reverberation. 408 * A lower density creates a hollow sound that is useful for simulating small reverberation 409 * spaces such as bathrooms. 410 * @param density density specified using a permille scale. The valid range is [0, 1000]. 411 * A value of 1000 o/oo indicates a natural sounding reverberation. Values below this level 412 * produce a more colored effect. 413 * @throws IllegalStateException 414 * @throws IllegalArgumentException 415 * @throws UnsupportedOperationException 416 */ 417 public void setDensity(short density) 418 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 419 byte[] param = shortToByteArray(density); 420 checkStatus(setParameter(PARAM_DENSITY, param)); 421 } 422 423 /** 424 * Gets the density level. 425 * @return the density level. See {@link #setDiffusion(short)} for units. 426 * @throws IllegalStateException 427 * @throws IllegalArgumentException 428 * @throws UnsupportedOperationException 429 */ 430 public short getDensity() 431 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 432 byte[] param = new byte[2]; 433 checkStatus(getParameter(PARAM_DENSITY, param)); 434 return byteArrayToShort(param); 435 } 436 437 438 /** 439 * The OnParameterChangeListener interface defines a method called by the EnvironmentalReverb 440 * when a parameter value has changed. 441 */ 442 public interface OnParameterChangeListener { 443 /** 444 * Method called when a parameter value has changed. The method is called only if the 445 * parameter was changed by another application having the control of the same 446 * EnvironmentalReverb engine. 447 * @param effect the EnvironmentalReverb on which the interface is registered. 448 * @param status status of the set parameter operation. 449 * @param param ID of the modified parameter. See {@link #PARAM_ROOM_LEVEL} ... 450 * @param value the new parameter value. 451 */ 452 void onParameterChange(EnvironmentalReverb effect, int status, int param, int value); 453 } 454 455 /** 456 * Listener used internally to receive unformatted parameter change events from AudioEffect 457 * super class. 458 */ 459 private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { 460 private BaseParameterListener() { 461 462 } 463 public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { 464 OnParameterChangeListener l = null; 465 466 synchronized (mParamListenerLock) { 467 if (mParamListener != null) { 468 l = mParamListener; 469 } 470 } 471 if (l != null) { 472 int p = -1; 473 int v = -1; 474 475 if (param.length == 4) { 476 p = byteArrayToInt(param, 0); 477 } 478 if (value.length == 2) { 479 v = (int)byteArrayToShort(value, 0); 480 } else if (value.length == 4) { 481 v = byteArrayToInt(value, 0); 482 } 483 if (p != -1 && v != -1) { 484 l.onParameterChange(EnvironmentalReverb.this, status, p, v); 485 } 486 } 487 } 488 } 489 490 /** 491 * Registers an OnParameterChangeListener interface. 492 * @param listener OnParameterChangeListener interface registered 493 */ 494 public void setParameterListener(OnParameterChangeListener listener) { 495 synchronized (mParamListenerLock) { 496 if (mParamListener == null) { 497 mParamListener = listener; 498 mBaseParamListener = new BaseParameterListener(); 499 super.setParameterListener(mBaseParamListener); 500 } 501 } 502 } 503 504 /** 505 * The Settings class regroups all environmental reverb parameters. It is used in 506 * conjuntion with getProperties() and setProperties() methods to backup and restore 507 * all parameters in a single call. 508 */ 509 public static class Settings { 510 public short roomLevel; 511 public short roomHFLevel; 512 public int decayTime; 513 public short decayHFRatio; 514 public short reflectionsLevel; 515 public int reflectionsDelay; 516 public short reverbLevel; 517 public int reverbDelay; 518 public short diffusion; 519 public short density; 520 521 public Settings() { 522 } 523 524 /** 525 * Settings class constructor from a key=value; pairs formatted string. The string is 526 * typically returned by Settings.toString() method. 527 * @throws IllegalArgumentException if the string is not correctly formatted. 528 */ 529 public Settings(String settings) { 530 StringTokenizer st = new StringTokenizer(settings, "=;"); 531 int tokens = st.countTokens(); 532 if (st.countTokens() != 21) { 533 throw new IllegalArgumentException("settings: " + settings); 534 } 535 String key = st.nextToken(); 536 if (!key.equals("EnvironmentalReverb")) { 537 throw new IllegalArgumentException( 538 "invalid settings for EnvironmentalReverb: " + key); 539 } 540 541 try { 542 key = st.nextToken(); 543 if (!key.equals("roomLevel")) { 544 throw new IllegalArgumentException("invalid key name: " + key); 545 } 546 roomLevel = Short.parseShort(st.nextToken()); 547 key = st.nextToken(); 548 if (!key.equals("roomHFLevel")) { 549 throw new IllegalArgumentException("invalid key name: " + key); 550 } 551 roomHFLevel = Short.parseShort(st.nextToken()); 552 key = st.nextToken(); 553 if (!key.equals("decayTime")) { 554 throw new IllegalArgumentException("invalid key name: " + key); 555 } 556 decayTime = Integer.parseInt(st.nextToken()); 557 key = st.nextToken(); 558 if (!key.equals("decayHFRatio")) { 559 throw new IllegalArgumentException("invalid key name: " + key); 560 } 561 decayHFRatio = Short.parseShort(st.nextToken()); 562 key = st.nextToken(); 563 if (!key.equals("reflectionsLevel")) { 564 throw new IllegalArgumentException("invalid key name: " + key); 565 } 566 reflectionsLevel = Short.parseShort(st.nextToken()); 567 key = st.nextToken(); 568 if (!key.equals("reflectionsDelay")) { 569 throw new IllegalArgumentException("invalid key name: " + key); 570 } 571 reflectionsDelay = Integer.parseInt(st.nextToken()); 572 key = st.nextToken(); 573 if (!key.equals("reverbLevel")) { 574 throw new IllegalArgumentException("invalid key name: " + key); 575 } 576 reverbLevel = Short.parseShort(st.nextToken()); 577 key = st.nextToken(); 578 if (!key.equals("reverbDelay")) { 579 throw new IllegalArgumentException("invalid key name: " + key); 580 } 581 reverbDelay = Integer.parseInt(st.nextToken()); 582 key = st.nextToken(); 583 if (!key.equals("diffusion")) { 584 throw new IllegalArgumentException("invalid key name: " + key); 585 } 586 diffusion = Short.parseShort(st.nextToken()); 587 key = st.nextToken(); 588 if (!key.equals("density")) { 589 throw new IllegalArgumentException("invalid key name: " + key); 590 } 591 density = Short.parseShort(st.nextToken()); 592 } catch (NumberFormatException nfe) { 593 throw new IllegalArgumentException("invalid value for key: " + key); 594 } 595 } 596 597 @Override 598 public String toString() { 599 return new String ( 600 "EnvironmentalReverb"+ 601 ";roomLevel="+Short.toString(roomLevel)+ 602 ";roomHFLevel="+Short.toString(roomHFLevel)+ 603 ";decayTime="+Integer.toString(decayTime)+ 604 ";decayHFRatio="+Short.toString(decayHFRatio)+ 605 ";reflectionsLevel="+Short.toString(reflectionsLevel)+ 606 ";reflectionsDelay="+Integer.toString(reflectionsDelay)+ 607 ";reverbLevel="+Short.toString(reverbLevel)+ 608 ";reverbDelay="+Integer.toString(reverbDelay)+ 609 ";diffusion="+Short.toString(diffusion)+ 610 ";density="+Short.toString(density) 611 ); 612 } 613 }; 614 615 // Keep this in sync with sizeof(s_reverb_settings) defined in 616 // frameworks/base/include/media/EffectEnvironmentalReverbApi.h 617 static private int PROPERTY_SIZE = 26; 618 619 /** 620 * Gets the environmental reverb properties. This method is useful when a snapshot of current 621 * reverb settings must be saved by the application. 622 * @return an EnvironmentalReverb.Settings object containing all current parameters values 623 * @throws IllegalStateException 624 * @throws IllegalArgumentException 625 * @throws UnsupportedOperationException 626 */ 627 public EnvironmentalReverb.Settings getProperties() 628 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 629 byte[] param = new byte[PROPERTY_SIZE]; 630 checkStatus(getParameter(PARAM_PROPERTIES, param)); 631 Settings settings = new Settings(); 632 settings.roomLevel = byteArrayToShort(param, 0); 633 settings.roomHFLevel = byteArrayToShort(param, 2); 634 settings.decayTime = byteArrayToInt(param, 4); 635 settings.decayHFRatio = byteArrayToShort(param, 8); 636 settings.reflectionsLevel = byteArrayToShort(param, 10); 637 settings.reflectionsDelay = byteArrayToInt(param, 12); 638 settings.reverbLevel = byteArrayToShort(param, 16); 639 settings.reverbDelay = byteArrayToInt(param, 18); 640 settings.diffusion = byteArrayToShort(param, 22); 641 settings.density = byteArrayToShort(param, 24); 642 return settings; 643 } 644 645 /** 646 * Sets the environmental reverb properties. This method is useful when reverb settings have to 647 * be applied from a previous backup. 648 * @param settings a EnvironmentalReverb.Settings object containing the properties to apply 649 * @throws IllegalStateException 650 * @throws IllegalArgumentException 651 * @throws UnsupportedOperationException 652 */ 653 public void setProperties(EnvironmentalReverb.Settings settings) 654 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 655 656 byte[] param = concatArrays(shortToByteArray(settings.roomLevel), 657 shortToByteArray(settings.roomHFLevel), 658 intToByteArray(settings.decayTime), 659 shortToByteArray(settings.decayHFRatio), 660 shortToByteArray(settings.reflectionsLevel), 661 intToByteArray(settings.reflectionsDelay), 662 shortToByteArray(settings.reverbLevel), 663 intToByteArray(settings.reverbDelay), 664 shortToByteArray(settings.diffusion), 665 shortToByteArray(settings.density)); 666 667 checkStatus(setParameter(PARAM_PROPERTIES, param)); 668 } 669 } 670