• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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