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.media.audiofx.AudioEffect;
     20 import android.util.Log;
     21 
     22 import java.util.StringTokenizer;
     23 
     24 
     25 /**
     26  * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
     27  * to a simple equalizer but limited to one band amplification in the low frequency range.
     28  * <p>An application creates a BassBoost object to instantiate and control a bass boost engine in
     29  * the audio framework.
     30  * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly
     31  * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
     32  * for the SLBassBoostItf interface. Please refer to this specification for more details.
     33  * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session
     34  * ID of this AudioTrack or MediaPlayer when constructing the BassBoost.
     35  * <p>NOTE: attaching a BassBoost to the global audio output mix by use of session 0 is deprecated.
     36  * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions.
     37  * <p>See {@link android.media.audiofx.AudioEffect} class for more details on
     38  * controlling audio effects.
     39  */
     40 
     41 public class BassBoost extends AudioEffect {
     42 
     43     private final static String TAG = "BassBoost";
     44 
     45     // These constants must be synchronized with those in
     46     // frameworks/base/include/media/EffectBassBoostApi.h
     47     /**
     48      * Is strength parameter supported by bass boost engine. Parameter ID for getParameter().
     49      */
     50     public static final int PARAM_STRENGTH_SUPPORTED = 0;
     51     /**
     52      * Bass boost effect strength. Parameter ID for
     53      * {@link android.media.audiofx.BassBoost.OnParameterChangeListener}
     54      */
     55     public static final int PARAM_STRENGTH = 1;
     56 
     57     /**
     58      * Indicates if strength parameter is supported by the bass boost engine
     59      */
     60     private boolean mStrengthSupported = false;
     61 
     62     /**
     63      * Registered listener for parameter changes.
     64      */
     65     private OnParameterChangeListener mParamListener = null;
     66 
     67     /**
     68      * Listener used internally to to receive raw parameter change event from AudioEffect super class
     69      */
     70     private BaseParameterListener mBaseParamListener = null;
     71 
     72     /**
     73      * Lock for access to mParamListener
     74      */
     75     private final Object mParamListenerLock = new Object();
     76 
     77     /**
     78      * Class constructor.
     79      * @param priority the priority level requested by the application for controlling the BassBoost
     80      * engine. As the same engine can be shared by several applications, this parameter indicates
     81      * how much the requesting application needs control of effect parameters. The normal priority
     82      * is 0, above normal is a positive number, below normal a negative number.
     83      * @param audioSession system wide unique audio session identifier. The BassBoost will be
     84      * attached to the MediaPlayer or AudioTrack in the same audio session.
     85      *
     86      * @throws java.lang.IllegalStateException
     87      * @throws java.lang.IllegalArgumentException
     88      * @throws java.lang.UnsupportedOperationException
     89      * @throws java.lang.RuntimeException
     90      */
     91     public BassBoost(int priority, int audioSession)
     92     throws IllegalStateException, IllegalArgumentException,
     93            UnsupportedOperationException, RuntimeException {
     94         super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession);
     95 
     96         if (audioSession == 0) {
     97             Log.w(TAG, "WARNING: attaching a BassBoost to global output mix is deprecated!");
     98         }
     99 
    100         int[] value = new int[1];
    101         checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
    102         mStrengthSupported = (value[0] != 0);
    103     }
    104 
    105     /**
    106      * Indicates whether setting strength is supported. If this method returns false, only one
    107      * strength is supported and the setStrength() method always rounds to that value.
    108      * @return true is strength parameter is supported, false otherwise
    109      */
    110     public boolean getStrengthSupported() {
    111        return mStrengthSupported;
    112     }
    113 
    114     /**
    115      * Sets the strength of the bass boost effect. If the implementation does not support per mille
    116      * accuracy for setting the strength, it is allowed to round the given strength to the nearest
    117      * supported value. You can use the {@link #getRoundedStrength()} method to query the
    118      * (possibly rounded) value that was actually set.
    119      * @param strength strength of the effect. The valid range for strength strength is [0, 1000],
    120      * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
    121      * @throws IllegalStateException
    122      * @throws IllegalArgumentException
    123      * @throws UnsupportedOperationException
    124      */
    125     public void setStrength(short strength)
    126     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
    127         checkStatus(setParameter(PARAM_STRENGTH, strength));
    128     }
    129 
    130     /**
    131      * Gets the current strength of the effect.
    132      * @return the strength of the effect. The valid range for strength is [0, 1000], where 0 per
    133      * mille designates the mildest effect and 1000 per mille the strongest
    134      * @throws IllegalStateException
    135      * @throws IllegalArgumentException
    136      * @throws UnsupportedOperationException
    137      */
    138     public short getRoundedStrength()
    139     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
    140         short[] value = new short[1];
    141         checkStatus(getParameter(PARAM_STRENGTH, value));
    142         return value[0];
    143     }
    144 
    145     /**
    146      * The OnParameterChangeListener interface defines a method called by the BassBoost when a
    147      * parameter value has changed.
    148      */
    149     public interface OnParameterChangeListener  {
    150         /**
    151          * Method called when a parameter value has changed. The method is called only if the
    152          * parameter was changed by another application having the control of the same
    153          * BassBoost engine.
    154          * @param effect the BassBoost on which the interface is registered.
    155          * @param status status of the set parameter operation.
    156          * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
    157          * @param value the new parameter value.
    158          */
    159         void onParameterChange(BassBoost effect, int status, int param, short value);
    160     }
    161 
    162     /**
    163      * Listener used internally to receive unformatted parameter change events from AudioEffect
    164      * super class.
    165      */
    166     private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
    167         private BaseParameterListener() {
    168 
    169         }
    170         public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
    171             OnParameterChangeListener l = null;
    172 
    173             synchronized (mParamListenerLock) {
    174                 if (mParamListener != null) {
    175                     l = mParamListener;
    176                 }
    177             }
    178             if (l != null) {
    179                 int p = -1;
    180                 short v = -1;
    181 
    182                 if (param.length == 4) {
    183                     p = byteArrayToInt(param, 0);
    184                 }
    185                 if (value.length == 2) {
    186                     v = byteArrayToShort(value, 0);
    187                 }
    188                 if (p != -1 && v != -1) {
    189                     l.onParameterChange(BassBoost.this, status, p, v);
    190                 }
    191             }
    192         }
    193     }
    194 
    195     /**
    196      * Registers an OnParameterChangeListener interface.
    197      * @param listener OnParameterChangeListener interface registered
    198      */
    199     public void setParameterListener(OnParameterChangeListener listener) {
    200         synchronized (mParamListenerLock) {
    201             if (mParamListener == null) {
    202                 mParamListener = listener;
    203                 mBaseParamListener = new BaseParameterListener();
    204                 super.setParameterListener(mBaseParamListener);
    205             }
    206         }
    207     }
    208 
    209     /**
    210      * The Settings class regroups all bass boost parameters. It is used in
    211      * conjuntion with getProperties() and setProperties() methods to backup and restore
    212      * all parameters in a single call.
    213      */
    214     public static class Settings {
    215         public short strength;
    216 
    217         public Settings() {
    218         }
    219 
    220         /**
    221          * Settings class constructor from a key=value; pairs formatted string. The string is
    222          * typically returned by Settings.toString() method.
    223          * @throws IllegalArgumentException if the string is not correctly formatted.
    224          */
    225         public Settings(String settings) {
    226             StringTokenizer st = new StringTokenizer(settings, "=;");
    227             int tokens = st.countTokens();
    228             if (st.countTokens() != 3) {
    229                 throw new IllegalArgumentException("settings: " + settings);
    230             }
    231             String key = st.nextToken();
    232             if (!key.equals("BassBoost")) {
    233                 throw new IllegalArgumentException(
    234                         "invalid settings for BassBoost: " + key);
    235             }
    236             try {
    237                 key = st.nextToken();
    238                 if (!key.equals("strength")) {
    239                     throw new IllegalArgumentException("invalid key name: " + key);
    240                 }
    241                 strength = Short.parseShort(st.nextToken());
    242              } catch (NumberFormatException nfe) {
    243                 throw new IllegalArgumentException("invalid value for key: " + key);
    244             }
    245         }
    246 
    247         @Override
    248         public String toString() {
    249             String str = new String (
    250                     "BassBoost"+
    251                     ";strength="+Short.toString(strength)
    252                     );
    253             return str;
    254         }
    255     };
    256 
    257 
    258     /**
    259      * Gets the bass boost properties. This method is useful when a snapshot of current
    260      * bass boost settings must be saved by the application.
    261      * @return a BassBoost.Settings object containing all current parameters values
    262      * @throws IllegalStateException
    263      * @throws IllegalArgumentException
    264      * @throws UnsupportedOperationException
    265      */
    266     public BassBoost.Settings getProperties()
    267     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
    268         Settings settings = new Settings();
    269         short[] value = new short[1];
    270         checkStatus(getParameter(PARAM_STRENGTH, value));
    271         settings.strength = value[0];
    272         return settings;
    273     }
    274 
    275     /**
    276      * Sets the bass boost properties. This method is useful when bass boost settings have to
    277      * be applied from a previous backup.
    278      * @param settings a BassBoost.Settings object containing the properties to apply
    279      * @throws IllegalStateException
    280      * @throws IllegalArgumentException
    281      * @throws UnsupportedOperationException
    282      */
    283     public void setProperties(BassBoost.Settings settings)
    284     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
    285         checkStatus(setParameter(PARAM_STRENGTH, settings.strength));
    286     }
    287 }
    288