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.media.audiofx.AudioEffect; 20 import java.util.StringTokenizer; 21 22 23 /** 24 * A sound generated within a room travels in many directions. The listener first hears the 25 * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound 26 * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after 27 * undergoing more and more reflections, individual reflections become indistinguishable and 28 * the listener hears continuous reverberation that decays over time. 29 * Reverb is vital for modeling a listener's environment. It can be used in music applications 30 * to simulate music being played back in various environments, or in games to immerse the 31 * listener within the game's environment. 32 * The PresetReverb class allows an application to configure the global reverb using a reverb preset. 33 * This is primarily used for adding some reverb in a music playback context. Applications 34 * requiring control over a more advanced environmental reverb are advised to use the 35 * {@link android.media.audiofx.EnvironmentalReverb} class. 36 * <p>An application creates a PresetReverb object to instantiate and control a reverb engine in the 37 * audio framework. 38 * <p>The methods, parameter types and units exposed by the PresetReverb implementation are 39 * directly mapping those defined by the OpenSL ES 1.0.1 Specification 40 * (http://www.khronos.org/opensles/) for the SLPresetReverbItf interface. 41 * Please refer to this specification for more details. 42 * <p>The PresetReverb is an output mix auxiliary effect and should be created on 43 * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect, 44 * they must be explicitely attached to it and a send level must be specified. Use the effect ID 45 * returned by getId() method to designate this particular effect when attaching it to the 46 * MediaPlayer or AudioTrack. 47 * <p>Creating a reverb on the output mix (audio session 0) requires permission 48 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} 49 * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling 50 * audio effects. 51 */ 52 53 public class PresetReverb extends AudioEffect { 54 55 private final static String TAG = "PresetReverb"; 56 57 // These constants must be synchronized with those in 58 // frameworks/base/include/media/EffectPresetReverbApi.h 59 60 /** 61 * Preset. Parameter ID for 62 * {@link android.media.audiofx.PresetReverb.OnParameterChangeListener} 63 */ 64 public static final int PARAM_PRESET = 0; 65 66 /** 67 * No reverb or reflections 68 */ 69 public static final short PRESET_NONE = 0; 70 /** 71 * Reverb preset representing a small room less than five meters in length 72 */ 73 public static final short PRESET_SMALLROOM = 1; 74 /** 75 * Reverb preset representing a medium room with a length of ten meters or less 76 */ 77 public static final short PRESET_MEDIUMROOM = 2; 78 /** 79 * Reverb preset representing a large-sized room suitable for live performances 80 */ 81 public static final short PRESET_LARGEROOM = 3; 82 /** 83 * Reverb preset representing a medium-sized hall 84 */ 85 public static final short PRESET_MEDIUMHALL = 4; 86 /** 87 * Reverb preset representing a large-sized hall suitable for a full orchestra 88 */ 89 public static final short PRESET_LARGEHALL = 5; 90 /** 91 * Reverb preset representing a synthesis of the traditional plate reverb 92 */ 93 public static final short PRESET_PLATE = 6; 94 95 /** 96 * Registered listener for parameter changes. 97 */ 98 private OnParameterChangeListener mParamListener = null; 99 100 /** 101 * Listener used internally to to receive raw parameter change event from AudioEffect super class 102 */ 103 private BaseParameterListener mBaseParamListener = null; 104 105 /** 106 * Lock for access to mParamListener 107 */ 108 private final Object mParamListenerLock = new Object(); 109 110 /** 111 * Class constructor. 112 * @param priority the priority level requested by the application for controlling the 113 * PresetReverb engine. As the same engine can be shared by several applications, this 114 * parameter indicates how much the requesting application needs control of effect parameters. 115 * The normal priority is 0, above normal is a positive number, below normal a negative number. 116 * @param audioSession system wide unique audio session identifier. If audioSession 117 * is not 0, the PresetReverb will be attached to the MediaPlayer or AudioTrack in the 118 * same audio session. Otherwise, the PresetReverb will apply to the output mix. 119 * As the PresetReverb is an auxiliary effect it is recommended to instantiate it on 120 * audio session 0 and to attach it to the MediaPLayer auxiliary output. 121 * 122 * @throws java.lang.IllegalArgumentException 123 * @throws java.lang.UnsupportedOperationException 124 * @throws java.lang.RuntimeException 125 */ PresetReverb(int priority, int audioSession)126 public PresetReverb(int priority, int audioSession) 127 throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { 128 super(EFFECT_TYPE_PRESET_REVERB, EFFECT_TYPE_NULL, priority, audioSession); 129 } 130 131 /** 132 * Enables a preset on the reverb. 133 * <p>The reverb PRESET_NONE disables any reverb from the current output but does not free the 134 * resources associated with the reverb. For an application to signal to the implementation 135 * to free the resources, it must call the release() method. 136 * @param preset this must be one of the the preset constants defined in this class. 137 * e.g. {@link #PRESET_SMALLROOM} 138 * @throws IllegalStateException 139 * @throws IllegalArgumentException 140 * @throws UnsupportedOperationException 141 */ setPreset(short preset)142 public void setPreset(short preset) 143 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 144 checkStatus(setParameter(PARAM_PRESET, preset)); 145 } 146 147 /** 148 * Gets current reverb preset. 149 * @return the preset that is set at the moment. 150 * @throws IllegalStateException 151 * @throws IllegalArgumentException 152 * @throws UnsupportedOperationException 153 */ getPreset()154 public short getPreset() 155 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 156 short[] value = new short[1]; 157 checkStatus(getParameter(PARAM_PRESET, value)); 158 return value[0]; 159 } 160 161 /** 162 * The OnParameterChangeListener interface defines a method called by the PresetReverb 163 * when a parameter value has changed. 164 */ 165 public interface OnParameterChangeListener { 166 /** 167 * Method called when a parameter value has changed. The method is called only if the 168 * parameter was changed by another application having the control of the same 169 * PresetReverb engine. 170 * @param effect the PresetReverb on which the interface is registered. 171 * @param status status of the set parameter operation. 172 * @param param ID of the modified parameter. See {@link #PARAM_PRESET} ... 173 * @param value the new parameter value. 174 */ onParameterChange(PresetReverb effect, int status, int param, short value)175 void onParameterChange(PresetReverb effect, int status, int param, short value); 176 } 177 178 /** 179 * Listener used internally to receive unformatted parameter change events from AudioEffect 180 * super class. 181 */ 182 private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { BaseParameterListener()183 private BaseParameterListener() { 184 185 } onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value)186 public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { 187 OnParameterChangeListener l = null; 188 189 synchronized (mParamListenerLock) { 190 if (mParamListener != null) { 191 l = mParamListener; 192 } 193 } 194 if (l != null) { 195 int p = -1; 196 short v = -1; 197 198 if (param.length == 4) { 199 p = byteArrayToInt(param, 0); 200 } 201 if (value.length == 2) { 202 v = byteArrayToShort(value, 0); 203 } 204 if (p != -1 && v != -1) { 205 l.onParameterChange(PresetReverb.this, status, p, v); 206 } 207 } 208 } 209 } 210 211 /** 212 * Registers an OnParameterChangeListener interface. 213 * @param listener OnParameterChangeListener interface registered 214 */ setParameterListener(OnParameterChangeListener listener)215 public void setParameterListener(OnParameterChangeListener listener) { 216 synchronized (mParamListenerLock) { 217 if (mParamListener == null) { 218 mParamListener = listener; 219 mBaseParamListener = new BaseParameterListener(); 220 super.setParameterListener(mBaseParamListener); 221 } 222 } 223 } 224 225 /** 226 * The Settings class regroups all preset reverb parameters. It is used in 227 * conjuntion with getProperties() and setProperties() methods to backup and restore 228 * all parameters in a single call. 229 */ 230 public static class Settings { 231 public short preset; 232 Settings()233 public Settings() { 234 } 235 236 /** 237 * Settings class constructor from a key=value; pairs formatted string. The string is 238 * typically returned by Settings.toString() method. 239 * @throws IllegalArgumentException if the string is not correctly formatted. 240 */ Settings(String settings)241 public Settings(String settings) { 242 StringTokenizer st = new StringTokenizer(settings, "=;"); 243 int tokens = st.countTokens(); 244 if (st.countTokens() != 3) { 245 throw new IllegalArgumentException("settings: " + settings); 246 } 247 String key = st.nextToken(); 248 if (!key.equals("PresetReverb")) { 249 throw new IllegalArgumentException( 250 "invalid settings for PresetReverb: " + key); 251 } 252 try { 253 key = st.nextToken(); 254 if (!key.equals("preset")) { 255 throw new IllegalArgumentException("invalid key name: " + key); 256 } 257 preset = Short.parseShort(st.nextToken()); 258 } catch (NumberFormatException nfe) { 259 throw new IllegalArgumentException("invalid value for key: " + key); 260 } 261 } 262 263 @Override toString()264 public String toString() { 265 String str = new String ( 266 "PresetReverb"+ 267 ";preset="+Short.toString(preset) 268 ); 269 return str; 270 } 271 }; 272 273 274 /** 275 * Gets the preset reverb properties. This method is useful when a snapshot of current 276 * preset reverb settings must be saved by the application. 277 * @return a PresetReverb.Settings object containing all current parameters values 278 * @throws IllegalStateException 279 * @throws IllegalArgumentException 280 * @throws UnsupportedOperationException 281 */ getProperties()282 public PresetReverb.Settings getProperties() 283 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 284 Settings settings = new Settings(); 285 short[] value = new short[1]; 286 checkStatus(getParameter(PARAM_PRESET, value)); 287 settings.preset = value[0]; 288 return settings; 289 } 290 291 /** 292 * Sets the preset reverb properties. This method is useful when preset reverb settings have to 293 * be applied from a previous backup. 294 * @param settings a PresetReverb.Settings object containing the properties to apply 295 * @throws IllegalStateException 296 * @throws IllegalArgumentException 297 * @throws UnsupportedOperationException 298 */ setProperties(PresetReverb.Settings settings)299 public void setProperties(PresetReverb.Settings settings) 300 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 301 checkStatus(setParameter(PARAM_PRESET, settings.preset)); 302 } 303 } 304