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