• 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.media.audiofx.AudioEffect;
20 import android.util.Log;
21 
22 import java.util.StringTokenizer;
23 
24 
25 /**
26  * An Equalizer is used to alter the frequency response of a particular music source or of the main
27  * output mix.
28  * <p>An application creates an Equalizer object to instantiate and control an Equalizer engine
29  * in the audio framework. The application can either simply use predefined presets or have a more
30  * precise control of the gain in each frequency band controlled by the equalizer.
31  * <p>The methods, parameter types and units exposed by the Equalizer implementation are directly
32  * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
33  * for the SLEqualizerItf interface. Please refer to this specification for more details.
34  * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session
35  * ID of this AudioTrack or MediaPlayer when constructing the Equalizer.
36  * <p>NOTE: attaching an Equalizer to the global audio output mix by use of session 0 is deprecated.
37  * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions.
38  * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio
39  * effects.
40  */
41 
42 public class Equalizer extends AudioEffect {
43 
44     private final static String TAG = "Equalizer";
45 
46     // These constants must be synchronized with those in
47     // frameworks/base/include/media/EffectEqualizerApi.h
48     /**
49      * Number of bands. Parameter ID for OnParameterChangeListener
50      */
51     public static final int PARAM_NUM_BANDS = 0;
52     /**
53      * Band level range. Parameter ID for OnParameterChangeListener
54      */
55     public static final int PARAM_LEVEL_RANGE = 1;
56     /**
57      * Band level. Parameter ID for OnParameterChangeListener
58      */
59     public static final int PARAM_BAND_LEVEL = 2;
60     /**
61      * Band center frequency. Parameter ID for OnParameterChangeListener
62      */
63     public static final int PARAM_CENTER_FREQ = 3;
64     /**
65      * Band frequency range. Parameter ID for
66      * {@link android.media.audiofx.Equalizer.OnParameterChangeListener}
67      */
68     public static final int PARAM_BAND_FREQ_RANGE = 4;
69     /**
70      * Band for a given frequency. Parameter ID for OnParameterChangeListener
71      *
72      */
73     public static final int PARAM_GET_BAND = 5;
74     /**
75      * Current preset. Parameter ID for OnParameterChangeListener
76      */
77     public static final int PARAM_CURRENT_PRESET = 6;
78     /**
79      * Request number of presets. Parameter ID for OnParameterChangeListener
80      */
81     public static final int PARAM_GET_NUM_OF_PRESETS = 7;
82     /**
83      * Request preset name. Parameter ID for OnParameterChangeListener
84      */
85     public static final int PARAM_GET_PRESET_NAME = 8;
86     // used by setProperties()/getProperties
87     private static final int PARAM_PROPERTIES = 9;
88     /**
89      * Maximum size for preset name
90      */
91     public static final int PARAM_STRING_SIZE_MAX = 32;
92 
93     /**
94      * Number of bands implemented by Equalizer engine
95      */
96     private short mNumBands = 0;
97 
98     /**
99      * Number of presets implemented by Equalizer engine
100      */
101     private int mNumPresets;
102     /**
103      * Names of presets implemented by Equalizer engine
104      */
105     private String[] mPresetNames;
106 
107     /**
108      * Registered listener for parameter changes.
109      */
110     private OnParameterChangeListener mParamListener = null;
111 
112     /**
113      * Listener used internally to to receive raw parameter change event from AudioEffect super class
114      */
115     private BaseParameterListener mBaseParamListener = null;
116 
117     /**
118      * Lock for access to mParamListener
119      */
120     private final Object mParamListenerLock = new Object();
121 
122     /**
123      * Class constructor.
124      * @param priority the priority level requested by the application for controlling the Equalizer
125      * engine. As the same engine can be shared by several applications, this parameter indicates
126      * how much the requesting application needs control of effect parameters. The normal priority
127      * is 0, above normal is a positive number, below normal a negative number.
128      * @param audioSession  system wide unique audio session identifier. The Equalizer will be
129      * attached to the MediaPlayer or AudioTrack in the same audio session.
130      *
131      * @throws java.lang.IllegalStateException
132      * @throws java.lang.IllegalArgumentException
133      * @throws java.lang.UnsupportedOperationException
134      * @throws java.lang.RuntimeException
135      */
Equalizer(int priority, int audioSession)136     public Equalizer(int priority, int audioSession)
137     throws IllegalStateException, IllegalArgumentException,
138            UnsupportedOperationException, RuntimeException {
139         super(EFFECT_TYPE_EQUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
140 
141         if (audioSession == 0) {
142             Log.w(TAG, "WARNING: attaching an Equalizer to global output mix is deprecated!");
143         }
144 
145         getNumberOfBands();
146 
147         mNumPresets = (int)getNumberOfPresets();
148 
149         if (mNumPresets != 0) {
150             mPresetNames = new String[mNumPresets];
151             byte[] value = new byte[PARAM_STRING_SIZE_MAX];
152             int[] param = new int[2];
153             param[0] = PARAM_GET_PRESET_NAME;
154             for (int i = 0; i < mNumPresets; i++) {
155                 param[1] = i;
156                 final int length = getParameter(param, value);
157                 checkStatus(length);
158                 try {
159                     mPresetNames[i] = new String(value, 0, length, "ISO-8859-1");
160                 } catch (java.io.UnsupportedEncodingException e) {
161                     Log.e(TAG, "preset name decode error");
162                 }
163             }
164         }
165     }
166 
167     /**
168      * Gets the number of frequency bands supported by the Equalizer engine.
169      * @return the number of bands
170      * @throws IllegalStateException
171      * @throws IllegalArgumentException
172      * @throws UnsupportedOperationException
173      */
getNumberOfBands()174     public short getNumberOfBands()
175     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
176         if (mNumBands != 0) {
177             return mNumBands;
178         }
179         int[] param = new int[1];
180         param[0] = PARAM_NUM_BANDS;
181         short[] result = new short[1];
182         checkStatus(getParameter(param, result));
183         mNumBands = result[0];
184         return mNumBands;
185     }
186 
187     /**
188      * Gets the level range for use by {@link #setBandLevel(short,short)}. The level is expressed in
189      * milliBel.
190      * @return the band level range in an array of short integers. The first element is the lower
191      * limit of the range, the second element the upper limit.
192      * @throws IllegalStateException
193      * @throws IllegalArgumentException
194      * @throws UnsupportedOperationException
195      */
getBandLevelRange()196     public short[] getBandLevelRange()
197     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
198         short[] result = new short[2];
199         checkStatus(getParameter(PARAM_LEVEL_RANGE, result));
200         return result;
201     }
202 
203     /**
204      * Sets the given equalizer band to the given gain value.
205      * @param band frequency band that will have the new gain. The numbering of the bands starts
206      * from 0 and ends at (number of bands - 1).
207      * @param level new gain in millibels that will be set to the given band. getBandLevelRange()
208      * will define the maximum and minimum values.
209      * @throws IllegalStateException
210      * @throws IllegalArgumentException
211      * @throws UnsupportedOperationException
212      * @see #getNumberOfBands()
213      */
setBandLevel(short band, short level)214     public void setBandLevel(short band, short level)
215     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
216         int[] param = new int[2];
217         short[] value = new short[1];
218 
219         param[0] = PARAM_BAND_LEVEL;
220         param[1] = (int)band;
221         value[0] = level;
222         checkStatus(setParameter(param, value));
223     }
224 
225     /**
226      * Gets the gain set for the given equalizer band.
227      * @param band frequency band whose gain is requested. The numbering of the bands starts
228      * from 0 and ends at (number of bands - 1).
229      * @return the gain in millibels of the given band.
230      * @throws IllegalStateException
231      * @throws IllegalArgumentException
232      * @throws UnsupportedOperationException
233      */
getBandLevel(short band)234     public short getBandLevel(short band)
235     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
236         int[] param = new int[2];
237         short[] result = new short[1];
238 
239         param[0] = PARAM_BAND_LEVEL;
240         param[1] = (int)band;
241         checkStatus(getParameter(param, result));
242 
243         return result[0];
244     }
245 
246 
247     /**
248      * Gets the center frequency of the given band.
249      * @param band frequency band whose center frequency is requested. The numbering of the bands
250      * starts from 0 and ends at (number of bands - 1).
251      * @return the center frequency in milliHertz
252      * @throws IllegalStateException
253      * @throws IllegalArgumentException
254      * @throws UnsupportedOperationException
255      */
getCenterFreq(short band)256     public int getCenterFreq(short band)
257     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
258         int[] param = new int[2];
259         int[] result = new int[1];
260 
261         param[0] = PARAM_CENTER_FREQ;
262         param[1] = (int)band;
263         checkStatus(getParameter(param, result));
264 
265         return result[0];
266     }
267 
268     /**
269      * Gets the frequency range of the given frequency band.
270      * @param band frequency band whose frequency range is requested. The numbering of the bands
271      * starts from 0 and ends at (number of bands - 1).
272      * @return the frequency range in millHertz in an array of integers. The first element is the
273      * lower limit of the range, the second element the upper limit.
274      * @throws IllegalStateException
275      * @throws IllegalArgumentException
276      * @throws UnsupportedOperationException
277      */
getBandFreqRange(short band)278     public int[] getBandFreqRange(short band)
279     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
280         int[] param = new int[2];
281         int[] result = new int[2];
282         param[0] = PARAM_BAND_FREQ_RANGE;
283         param[1] = (int)band;
284         checkStatus(getParameter(param, result));
285 
286         return result;
287     }
288 
289     /**
290      * Gets the band that has the most effect on the given frequency.
291      * @param frequency frequency in milliHertz which is to be equalized via the returned band.
292      * @return the frequency band that has most effect on the given frequency.
293      * @throws IllegalStateException
294      * @throws IllegalArgumentException
295      * @throws UnsupportedOperationException
296      */
getBand(int frequency)297     public short getBand(int frequency)
298     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
299         int[] param = new int[2];
300         short[] result = new short[1];
301 
302         param[0] = PARAM_GET_BAND;
303         param[1] = frequency;
304         checkStatus(getParameter(param, result));
305 
306         return result[0];
307     }
308 
309     /**
310      * Gets current preset.
311      * @return the preset that is set at the moment.
312      * @throws IllegalStateException
313      * @throws IllegalArgumentException
314      * @throws UnsupportedOperationException
315      */
getCurrentPreset()316     public short getCurrentPreset()
317     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
318         short[] result = new short[1];
319         checkStatus(getParameter(PARAM_CURRENT_PRESET, result));
320         return result[0];
321     }
322 
323     /**
324      * Sets the equalizer according to the given preset.
325      * @param preset new preset that will be taken into use. The valid range is [0,
326      * number of presets-1].
327      * @throws IllegalStateException
328      * @throws IllegalArgumentException
329      * @throws UnsupportedOperationException
330      * @see #getNumberOfPresets()
331      */
usePreset(short preset)332     public void usePreset(short preset)
333     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
334         checkStatus(setParameter(PARAM_CURRENT_PRESET, preset));
335     }
336 
337     /**
338      * Gets the total number of presets the equalizer supports. The presets will have indices
339      * [0, number of presets-1].
340      * @return the number of presets the equalizer supports.
341      * @throws IllegalStateException
342      * @throws IllegalArgumentException
343      * @throws UnsupportedOperationException
344      */
getNumberOfPresets()345     public short getNumberOfPresets()
346     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
347         short[] result = new short[1];
348         checkStatus(getParameter(PARAM_GET_NUM_OF_PRESETS, result));
349         return result[0];
350     }
351 
352     /**
353      * Gets the preset name based on the index.
354      * @param preset index of the preset. The valid range is [0, number of presets-1].
355      * @return a string containing the name of the given preset.
356      * @throws IllegalStateException
357      * @throws IllegalArgumentException
358      * @throws UnsupportedOperationException
359      */
getPresetName(short preset)360     public String getPresetName(short preset)
361     {
362         if (preset >= 0 && preset < mNumPresets) {
363             return mPresetNames[preset];
364         } else {
365             return "";
366         }
367     }
368 
369     /**
370      * The OnParameterChangeListener interface defines a method called by the Equalizer when a
371      * parameter value has changed.
372      */
373     public interface OnParameterChangeListener  {
374         /**
375          * Method called when a parameter value has changed. The method is called only if the
376          * parameter was changed by another application having the control of the same
377          * Equalizer engine.
378          * @param effect the Equalizer on which the interface is registered.
379          * @param status status of the set parameter operation.
380          * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ...
381          * @param param2 additional parameter qualifier (e.g the band for band level parameter).
382          * @param value the new parameter value.
383          */
onParameterChange(Equalizer effect, int status, int param1, int param2, int value)384         void onParameterChange(Equalizer effect, int status, int param1, int param2, int value);
385     }
386 
387     /**
388      * Listener used internally to receive unformatted parameter change events from AudioEffect
389      * super class.
390      */
391     private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
BaseParameterListener()392         private BaseParameterListener() {
393 
394         }
onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value)395         public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
396             OnParameterChangeListener l = null;
397 
398             synchronized (mParamListenerLock) {
399                 if (mParamListener != null) {
400                     l = mParamListener;
401                 }
402             }
403             if (l != null) {
404                 int p1 = -1;
405                 int p2 = -1;
406                 int v = -1;
407 
408                 if (param.length >= 4) {
409                     p1 = byteArrayToInt(param, 0);
410                     if (param.length >= 8) {
411                         p2 = byteArrayToInt(param, 4);
412                     }
413                 }
414                 if (value.length == 2) {
415                     v = (int)byteArrayToShort(value, 0);;
416                 } else if (value.length == 4) {
417                     v = byteArrayToInt(value, 0);
418                 }
419 
420                 if (p1 != -1 && v != -1) {
421                     l.onParameterChange(Equalizer.this, status, p1, p2, v);
422                 }
423             }
424         }
425     }
426 
427     /**
428      * Registers an OnParameterChangeListener interface.
429      * @param listener OnParameterChangeListener interface registered
430      */
setParameterListener(OnParameterChangeListener listener)431     public void setParameterListener(OnParameterChangeListener listener) {
432         synchronized (mParamListenerLock) {
433             if (mParamListener == null) {
434                 mParamListener = listener;
435                 mBaseParamListener = new BaseParameterListener();
436                 super.setParameterListener(mBaseParamListener);
437             }
438         }
439     }
440 
441     /**
442      * The Settings class regroups all equalizer parameters. It is used in
443      * conjuntion with getProperties() and setProperties() methods to backup and restore
444      * all parameters in a single call.
445      */
446     public static class Settings {
447         public short curPreset;
448         public short numBands = 0;
449         public short[] bandLevels = null;
450 
Settings()451         public Settings() {
452         }
453 
454         /**
455          * Settings class constructor from a key=value; pairs formatted string. The string is
456          * typically returned by Settings.toString() method.
457          * @throws IllegalArgumentException if the string is not correctly formatted.
458          */
Settings(String settings)459         public Settings(String settings) {
460             StringTokenizer st = new StringTokenizer(settings, "=;");
461             int tokens = st.countTokens();
462             if (st.countTokens() < 5) {
463                 throw new IllegalArgumentException("settings: " + settings);
464             }
465             String key = st.nextToken();
466             if (!key.equals("Equalizer")) {
467                 throw new IllegalArgumentException(
468                         "invalid settings for Equalizer: " + key);
469             }
470             try {
471                 key = st.nextToken();
472                 if (!key.equals("curPreset")) {
473                     throw new IllegalArgumentException("invalid key name: " + key);
474                 }
475                 curPreset = Short.parseShort(st.nextToken());
476                 key = st.nextToken();
477                 if (!key.equals("numBands")) {
478                     throw new IllegalArgumentException("invalid key name: " + key);
479                 }
480                 numBands = Short.parseShort(st.nextToken());
481                 if (st.countTokens() != numBands*2) {
482                     throw new IllegalArgumentException("settings: " + settings);
483                 }
484                 bandLevels = new short[numBands];
485                 for (int i = 0; i < numBands; i++) {
486                     key = st.nextToken();
487                     if (!key.equals("band"+(i+1)+"Level")) {
488                         throw new IllegalArgumentException("invalid key name: " + key);
489                     }
490                     bandLevels[i] = Short.parseShort(st.nextToken());
491                 }
492              } catch (NumberFormatException nfe) {
493                 throw new IllegalArgumentException("invalid value for key: " + key);
494             }
495         }
496 
497         @Override
toString()498         public String toString() {
499 
500             String str = new String (
501                     "Equalizer"+
502                     ";curPreset="+Short.toString(curPreset)+
503                     ";numBands="+Short.toString(numBands)
504                     );
505             for (int i = 0; i < numBands; i++) {
506                 str = str.concat(";band"+(i+1)+"Level="+Short.toString(bandLevels[i]));
507             }
508             return str;
509         }
510     };
511 
512 
513     /**
514      * Gets the equalizer properties. This method is useful when a snapshot of current
515      * equalizer settings must be saved by the application.
516      * @return an Equalizer.Settings object containing all current parameters values
517      * @throws IllegalStateException
518      * @throws IllegalArgumentException
519      * @throws UnsupportedOperationException
520      */
getProperties()521     public Equalizer.Settings getProperties()
522     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
523         byte[] param = new byte[4 + mNumBands * 2];
524         checkStatus(getParameter(PARAM_PROPERTIES, param));
525         Settings settings = new Settings();
526         settings.curPreset = byteArrayToShort(param, 0);
527         settings.numBands = byteArrayToShort(param, 2);
528         settings.bandLevels = new short[mNumBands];
529         for (int i = 0; i < mNumBands; i++) {
530             settings.bandLevels[i] = byteArrayToShort(param, 4 + 2*i);
531         }
532         return settings;
533     }
534 
535     /**
536      * Sets the equalizer properties. This method is useful when equalizer settings have to
537      * be applied from a previous backup.
538      * @param settings an Equalizer.Settings object containing the properties to apply
539      * @throws IllegalStateException
540      * @throws IllegalArgumentException
541      * @throws UnsupportedOperationException
542      */
setProperties(Equalizer.Settings settings)543     public void setProperties(Equalizer.Settings settings)
544     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
545         if (settings.numBands != settings.bandLevels.length ||
546             settings.numBands != mNumBands) {
547             throw new IllegalArgumentException("settings invalid band count: " +settings.numBands);
548         }
549 
550         byte[] param = concatArrays(shortToByteArray(settings.curPreset),
551                                     shortToByteArray(mNumBands));
552         for (int i = 0; i < mNumBands; i++) {
553             param = concatArrays(param,
554                                  shortToByteArray(settings.bandLevels[i]));
555         }
556         checkStatus(setParameter(PARAM_PROPERTIES, param));
557     }
558 }
559