| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.media.audiofx; |
| |
| import android.media.audiofx.AudioEffect; |
| import android.util.Log; |
| |
| import java.util.StringTokenizer; |
| |
| |
| /** |
| * An Equalizer is used to alter the frequency response of a particular music source or of the main |
| * output mix. |
| * <p>An application creates an Equalizer object to instantiate and control an Equalizer engine |
| * in the audio framework. The application can either simply use predefined presets or have a more |
| * precise control of the gain in each frequency band controlled by the equalizer. |
| * <p>The methods, parameter types and units exposed by the Equalizer implementation are directly |
| * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/) |
| * for the SLEqualizerItf interface. Please refer to this specification for more details. |
| * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session |
| * ID of this AudioTrack or MediaPlayer when constructing the Equalizer. |
| * <p>NOTE: attaching an Equalizer to the global audio output mix by use of session 0 is deprecated. |
| * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. |
| * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio |
| * effects. |
| */ |
| |
| public class Equalizer extends AudioEffect { |
| |
| private final static String TAG = "Equalizer"; |
| |
| // These constants must be synchronized with those in |
| // frameworks/base/include/media/EffectEqualizerApi.h |
| /** |
| * Number of bands. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_NUM_BANDS = 0; |
| /** |
| * Band level range. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_LEVEL_RANGE = 1; |
| /** |
| * Band level. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_BAND_LEVEL = 2; |
| /** |
| * Band center frequency. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_CENTER_FREQ = 3; |
| /** |
| * Band frequency range. Parameter ID for |
| * {@link android.media.audiofx.Equalizer.OnParameterChangeListener} |
| */ |
| public static final int PARAM_BAND_FREQ_RANGE = 4; |
| /** |
| * Band for a given frequency. Parameter ID for OnParameterChangeListener |
| * |
| */ |
| public static final int PARAM_GET_BAND = 5; |
| /** |
| * Current preset. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_CURRENT_PRESET = 6; |
| /** |
| * Request number of presets. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_GET_NUM_OF_PRESETS = 7; |
| /** |
| * Request preset name. Parameter ID for OnParameterChangeListener |
| */ |
| public static final int PARAM_GET_PRESET_NAME = 8; |
| // used by setProperties()/getProperties |
| private static final int PARAM_PROPERTIES = 9; |
| /** |
| * Maximum size for preset name |
| */ |
| public static final int PARAM_STRING_SIZE_MAX = 32; |
| |
| /** |
| * Number of bands implemented by Equalizer engine |
| */ |
| private short mNumBands = 0; |
| |
| /** |
| * Number of presets implemented by Equalizer engine |
| */ |
| private int mNumPresets; |
| /** |
| * Names of presets implemented by Equalizer engine |
| */ |
| private String[] mPresetNames; |
| |
| /** |
| * Registered listener for parameter changes. |
| */ |
| private OnParameterChangeListener mParamListener = null; |
| |
| /** |
| * Listener used internally to to receive raw parameter change event from AudioEffect super class |
| */ |
| private BaseParameterListener mBaseParamListener = null; |
| |
| /** |
| * Lock for access to mParamListener |
| */ |
| private final Object mParamListenerLock = new Object(); |
| |
| /** |
| * Class constructor. |
| * @param priority the priority level requested by the application for controlling the Equalizer |
| * engine. As the same engine can be shared by several applications, this parameter indicates |
| * how much the requesting application needs control of effect parameters. The normal priority |
| * is 0, above normal is a positive number, below normal a negative number. |
| * @param audioSession system wide unique audio session identifier. The Equalizer will be |
| * attached to the MediaPlayer or AudioTrack in the same audio session. |
| * |
| * @throws java.lang.IllegalStateException |
| * @throws java.lang.IllegalArgumentException |
| * @throws java.lang.UnsupportedOperationException |
| * @throws java.lang.RuntimeException |
| */ |
| public Equalizer(int priority, int audioSession) |
| throws IllegalStateException, IllegalArgumentException, |
| UnsupportedOperationException, RuntimeException { |
| super(EFFECT_TYPE_EQUALIZER, EFFECT_TYPE_NULL, priority, audioSession); |
| |
| if (audioSession == 0) { |
| Log.w(TAG, "WARNING: attaching an Equalizer to global output mix is deprecated!"); |
| } |
| |
| getNumberOfBands(); |
| |
| mNumPresets = (int)getNumberOfPresets(); |
| |
| if (mNumPresets != 0) { |
| mPresetNames = new String[mNumPresets]; |
| byte[] value = new byte[PARAM_STRING_SIZE_MAX]; |
| int[] param = new int[2]; |
| param[0] = PARAM_GET_PRESET_NAME; |
| for (int i = 0; i < mNumPresets; i++) { |
| param[1] = i; |
| checkStatus(getParameter(param, value)); |
| int length = 0; |
| while (value[length] != 0) length++; |
| try { |
| mPresetNames[i] = new String(value, 0, length, "ISO-8859-1"); |
| } catch (java.io.UnsupportedEncodingException e) { |
| Log.e(TAG, "preset name decode error"); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Gets the number of frequency bands supported by the Equalizer engine. |
| * @return the number of bands |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public short getNumberOfBands() |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| if (mNumBands != 0) { |
| return mNumBands; |
| } |
| int[] param = new int[1]; |
| param[0] = PARAM_NUM_BANDS; |
| short[] result = new short[1]; |
| checkStatus(getParameter(param, result)); |
| mNumBands = result[0]; |
| return mNumBands; |
| } |
| |
| /** |
| * Gets the level range for use by {@link #setBandLevel(short,short)}. The level is expressed in |
| * milliBel. |
| * @return the band level range in an array of short integers. The first element is the lower |
| * limit of the range, the second element the upper limit. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public short[] getBandLevelRange() |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| short[] result = new short[2]; |
| checkStatus(getParameter(PARAM_LEVEL_RANGE, result)); |
| return result; |
| } |
| |
| /** |
| * Sets the given equalizer band to the given gain value. |
| * @param band frequency band that will have the new gain. The numbering of the bands starts |
| * from 0 and ends at (number of bands - 1). |
| * @param level new gain in millibels that will be set to the given band. getBandLevelRange() |
| * will define the maximum and minimum values. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| * @see #getNumberOfBands() |
| */ |
| public void setBandLevel(short band, short level) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| int[] param = new int[2]; |
| short[] value = new short[1]; |
| |
| param[0] = PARAM_BAND_LEVEL; |
| param[1] = (int)band; |
| value[0] = level; |
| checkStatus(setParameter(param, value)); |
| } |
| |
| /** |
| * Gets the gain set for the given equalizer band. |
| * @param band frequency band whose gain is requested. The numbering of the bands starts |
| * from 0 and ends at (number of bands - 1). |
| * @return the gain in millibels of the given band. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public short getBandLevel(short band) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| int[] param = new int[2]; |
| short[] result = new short[1]; |
| |
| param[0] = PARAM_BAND_LEVEL; |
| param[1] = (int)band; |
| checkStatus(getParameter(param, result)); |
| |
| return result[0]; |
| } |
| |
| |
| /** |
| * Gets the center frequency of the given band. |
| * @param band frequency band whose center frequency is requested. The numbering of the bands |
| * starts from 0 and ends at (number of bands - 1). |
| * @return the center frequency in milliHertz |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public int getCenterFreq(short band) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| int[] param = new int[2]; |
| int[] result = new int[1]; |
| |
| param[0] = PARAM_CENTER_FREQ; |
| param[1] = (int)band; |
| checkStatus(getParameter(param, result)); |
| |
| return result[0]; |
| } |
| |
| /** |
| * Gets the frequency range of the given frequency band. |
| * @param band frequency band whose frequency range is requested. The numbering of the bands |
| * starts from 0 and ends at (number of bands - 1). |
| * @return the frequency range in millHertz in an array of integers. The first element is the |
| * lower limit of the range, the second element the upper limit. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public int[] getBandFreqRange(short band) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| int[] param = new int[2]; |
| int[] result = new int[2]; |
| param[0] = PARAM_BAND_FREQ_RANGE; |
| param[1] = (int)band; |
| checkStatus(getParameter(param, result)); |
| |
| return result; |
| } |
| |
| /** |
| * Gets the band that has the most effect on the given frequency. |
| * @param frequency frequency in milliHertz which is to be equalized via the returned band. |
| * @return the frequency band that has most effect on the given frequency. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public short getBand(int frequency) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| int[] param = new int[2]; |
| short[] result = new short[1]; |
| |
| param[0] = PARAM_GET_BAND; |
| param[1] = frequency; |
| checkStatus(getParameter(param, result)); |
| |
| return result[0]; |
| } |
| |
| /** |
| * Gets current preset. |
| * @return the preset that is set at the moment. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public short getCurrentPreset() |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| short[] result = new short[1]; |
| checkStatus(getParameter(PARAM_CURRENT_PRESET, result)); |
| return result[0]; |
| } |
| |
| /** |
| * Sets the equalizer according to the given preset. |
| * @param preset new preset that will be taken into use. The valid range is [0, |
| * number of presets-1]. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| * @see #getNumberOfPresets() |
| */ |
| public void usePreset(short preset) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| checkStatus(setParameter(PARAM_CURRENT_PRESET, preset)); |
| } |
| |
| /** |
| * Gets the total number of presets the equalizer supports. The presets will have indices |
| * [0, number of presets-1]. |
| * @return the number of presets the equalizer supports. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public short getNumberOfPresets() |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| short[] result = new short[1]; |
| checkStatus(getParameter(PARAM_GET_NUM_OF_PRESETS, result)); |
| return result[0]; |
| } |
| |
| /** |
| * Gets the preset name based on the index. |
| * @param preset index of the preset. The valid range is [0, number of presets-1]. |
| * @return a string containing the name of the given preset. |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public String getPresetName(short preset) |
| { |
| if (preset >= 0 && preset < mNumPresets) { |
| return mPresetNames[preset]; |
| } else { |
| return ""; |
| } |
| } |
| |
| /** |
| * The OnParameterChangeListener interface defines a method called by the Equalizer when a |
| * parameter value has changed. |
| */ |
| public interface OnParameterChangeListener { |
| /** |
| * Method called when a parameter value has changed. The method is called only if the |
| * parameter was changed by another application having the control of the same |
| * Equalizer engine. |
| * @param effect the Equalizer on which the interface is registered. |
| * @param status status of the set parameter operation. |
| * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ... |
| * @param param2 additional parameter qualifier (e.g the band for band level parameter). |
| * @param value the new parameter value. |
| */ |
| void onParameterChange(Equalizer effect, int status, int param1, int param2, int value); |
| } |
| |
| /** |
| * Listener used internally to receive unformatted parameter change events from AudioEffect |
| * super class. |
| */ |
| private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { |
| private BaseParameterListener() { |
| |
| } |
| public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { |
| OnParameterChangeListener l = null; |
| |
| synchronized (mParamListenerLock) { |
| if (mParamListener != null) { |
| l = mParamListener; |
| } |
| } |
| if (l != null) { |
| int p1 = -1; |
| int p2 = -1; |
| int v = -1; |
| |
| if (param.length >= 4) { |
| p1 = byteArrayToInt(param, 0); |
| if (param.length >= 8) { |
| p2 = byteArrayToInt(param, 4); |
| } |
| } |
| if (value.length == 2) { |
| v = (int)byteArrayToShort(value, 0);; |
| } else if (value.length == 4) { |
| v = byteArrayToInt(value, 0); |
| } |
| |
| if (p1 != -1 && v != -1) { |
| l.onParameterChange(Equalizer.this, status, p1, p2, v); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Registers an OnParameterChangeListener interface. |
| * @param listener OnParameterChangeListener interface registered |
| */ |
| public void setParameterListener(OnParameterChangeListener listener) { |
| synchronized (mParamListenerLock) { |
| if (mParamListener == null) { |
| mParamListener = listener; |
| mBaseParamListener = new BaseParameterListener(); |
| super.setParameterListener(mBaseParamListener); |
| } |
| } |
| } |
| |
| /** |
| * The Settings class regroups all equalizer parameters. It is used in |
| * conjuntion with getProperties() and setProperties() methods to backup and restore |
| * all parameters in a single call. |
| */ |
| public static class Settings { |
| public short curPreset; |
| public short numBands = 0; |
| public short[] bandLevels = null; |
| |
| public Settings() { |
| } |
| |
| /** |
| * Settings class constructor from a key=value; pairs formatted string. The string is |
| * typically returned by Settings.toString() method. |
| * @throws IllegalArgumentException if the string is not correctly formatted. |
| */ |
| public Settings(String settings) { |
| StringTokenizer st = new StringTokenizer(settings, "=;"); |
| int tokens = st.countTokens(); |
| if (st.countTokens() < 5) { |
| throw new IllegalArgumentException("settings: " + settings); |
| } |
| String key = st.nextToken(); |
| if (!key.equals("Equalizer")) { |
| throw new IllegalArgumentException( |
| "invalid settings for Equalizer: " + key); |
| } |
| try { |
| key = st.nextToken(); |
| if (!key.equals("curPreset")) { |
| throw new IllegalArgumentException("invalid key name: " + key); |
| } |
| curPreset = Short.parseShort(st.nextToken()); |
| key = st.nextToken(); |
| if (!key.equals("numBands")) { |
| throw new IllegalArgumentException("invalid key name: " + key); |
| } |
| numBands = Short.parseShort(st.nextToken()); |
| if (st.countTokens() != numBands*2) { |
| throw new IllegalArgumentException("settings: " + settings); |
| } |
| bandLevels = new short[numBands]; |
| for (int i = 0; i < numBands; i++) { |
| key = st.nextToken(); |
| if (!key.equals("band"+(i+1)+"Level")) { |
| throw new IllegalArgumentException("invalid key name: " + key); |
| } |
| bandLevels[i] = Short.parseShort(st.nextToken()); |
| } |
| } catch (NumberFormatException nfe) { |
| throw new IllegalArgumentException("invalid value for key: " + key); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| |
| String str = new String ( |
| "Equalizer"+ |
| ";curPreset="+Short.toString(curPreset)+ |
| ";numBands="+Short.toString(numBands) |
| ); |
| for (int i = 0; i < numBands; i++) { |
| str = str.concat(";band"+(i+1)+"Level="+Short.toString(bandLevels[i])); |
| } |
| return str; |
| } |
| }; |
| |
| |
| /** |
| * Gets the equalizer properties. This method is useful when a snapshot of current |
| * equalizer settings must be saved by the application. |
| * @return an Equalizer.Settings object containing all current parameters values |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public Equalizer.Settings getProperties() |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| byte[] param = new byte[4 + mNumBands * 2]; |
| checkStatus(getParameter(PARAM_PROPERTIES, param)); |
| Settings settings = new Settings(); |
| settings.curPreset = byteArrayToShort(param, 0); |
| settings.numBands = byteArrayToShort(param, 2); |
| settings.bandLevels = new short[mNumBands]; |
| for (int i = 0; i < mNumBands; i++) { |
| settings.bandLevels[i] = byteArrayToShort(param, 4 + 2*i); |
| } |
| return settings; |
| } |
| |
| /** |
| * Sets the equalizer properties. This method is useful when equalizer settings have to |
| * be applied from a previous backup. |
| * @param settings an Equalizer.Settings object containing the properties to apply |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * @throws UnsupportedOperationException |
| */ |
| public void setProperties(Equalizer.Settings settings) |
| throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { |
| if (settings.numBands != settings.bandLevels.length || |
| settings.numBands != mNumBands) { |
| throw new IllegalArgumentException("settings invalid band count: " +settings.numBands); |
| } |
| |
| byte[] param = concatArrays(shortToByteArray(settings.curPreset), |
| shortToByteArray(mNumBands)); |
| for (int i = 0; i < mNumBands; i++) { |
| param = concatArrays(param, |
| shortToByteArray(settings.bandLevels[i])); |
| } |
| checkStatus(setParameter(PARAM_PROPERTIES, param)); |
| } |
| } |