Home | History | Annotate | Download | only in audiofx
      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