| /* |
| * 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. |
| */ |
| |
| /* Equalizer implementation */ |
| |
| #include "sles_allinclusive.h" |
| #ifdef ANDROID |
| #include <audio_effects/effect_equalizer.h> |
| #endif |
| |
| #define MAX_EQ_PRESETS 3 |
| |
| #if !defined(ANDROID) |
| static const struct EqualizerBand EqualizerBands[MAX_EQ_BANDS] = { |
| {1000, 1500, 2000}, |
| {2000, 3000, 4000}, |
| {4000, 5500, 7000}, |
| {7000, 8000, 9000} |
| }; |
| |
| static const struct EqualizerPreset { |
| const char *mName; |
| SLmillibel mLevels[MAX_EQ_BANDS]; |
| } EqualizerPresets[MAX_EQ_PRESETS] = { |
| {"Default", {0, 0, 0, 0}}, |
| {"Bass", {500, 200, 100, 0}}, |
| {"Treble", {0, 100, 200, 500}} |
| }; |
| #endif |
| |
| |
| #if defined(ANDROID) |
| /** |
| * returns true if this interface is not associated with an initialized Equalizer effect |
| */ |
| static inline bool NO_EQ(IEqualizer* v) { |
| return (v->mEqEffect == 0); |
| } |
| #endif |
| |
| |
| static SLresult IEqualizer_SetEnabled(SLEqualizerItf self, SLboolean enabled) |
| { |
| SL_ENTER_INTERFACE |
| |
| IEqualizer *thiz = (IEqualizer *) self; |
| interface_lock_exclusive(thiz); |
| thiz->mEnabled = (SLboolean) enabled; |
| #if !defined(ANDROID) |
| result = SL_RESULT_SUCCESS; |
| #else |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| thiz->mEqEffect->setEnabled((bool) thiz->mEnabled); |
| result = android_fx_statusToResult(status); |
| } |
| #endif |
| interface_unlock_exclusive(thiz); |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_IsEnabled(SLEqualizerItf self, SLboolean *pEnabled) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pEnabled) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| interface_lock_exclusive(thiz); |
| SLboolean enabled = thiz->mEnabled; |
| #if !defined(ANDROID) |
| *pEnabled = enabled; |
| result = SL_RESULT_SUCCESS; |
| #else |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| *pEnabled = (SLboolean) thiz->mEqEffect->getEnabled(); |
| result = SL_RESULT_SUCCESS; |
| } |
| #endif |
| interface_unlock_exclusive(thiz); |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetNumberOfBands(SLEqualizerItf self, SLuint16 *pNumBands) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pNumBands) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| // Note: no lock, but OK because it is const |
| *pNumBands = thiz->mNumBands; |
| result = SL_RESULT_SUCCESS; |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetBandLevelRange(SLEqualizerItf self, SLmillibel *pMin, |
| SLmillibel *pMax) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pMin && NULL == pMax) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| // Note: no lock, but OK because it is const |
| if (NULL != pMin) |
| *pMin = thiz->mBandLevelRangeMin; |
| if (NULL != pMax) |
| *pMax = thiz->mBandLevelRangeMax; |
| result = SL_RESULT_SUCCESS; |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_SetBandLevel(SLEqualizerItf self, SLuint16 band, SLmillibel level) |
| { |
| SL_ENTER_INTERFACE |
| |
| IEqualizer *thiz = (IEqualizer *) self; |
| if (!(thiz->mBandLevelRangeMin <= level && level <= thiz->mBandLevelRangeMax) || |
| (band >= thiz->mNumBands)) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| interface_lock_exclusive(thiz); |
| #if !defined(ANDROID) |
| thiz->mLevels[band] = level; |
| thiz->mPreset = SL_EQUALIZER_UNDEFINED; |
| result = SL_RESULT_SUCCESS; |
| #else |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_setParam(thiz->mEqEffect, EQ_PARAM_BAND_LEVEL, band, &level); |
| result = android_fx_statusToResult(status); |
| } |
| #endif |
| interface_unlock_exclusive(thiz); |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetBandLevel(SLEqualizerItf self, SLuint16 band, SLmillibel *pLevel) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pLevel) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| // const, no lock needed |
| if (band >= thiz->mNumBands) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| SLmillibel level = 0; |
| interface_lock_shared(thiz); |
| #if !defined(ANDROID) |
| level = thiz->mLevels[band]; |
| result = SL_RESULT_SUCCESS; |
| #else |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_getParam(thiz->mEqEffect, EQ_PARAM_BAND_LEVEL, band, &level); |
| result = android_fx_statusToResult(status); |
| } |
| #endif |
| interface_unlock_shared(thiz); |
| *pLevel = level; |
| } |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetCenterFreq(SLEqualizerItf self, SLuint16 band, SLmilliHertz *pCenter) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pCenter) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| if (band >= thiz->mNumBands) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| #if !defined(ANDROID) |
| // Note: no lock, but OK because it is const |
| *pCenter = thiz->mBands[band].mCenter; |
| result = SL_RESULT_SUCCESS; |
| #else |
| SLmilliHertz center = 0; |
| interface_lock_shared(thiz); |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_getParam(thiz->mEqEffect, EQ_PARAM_CENTER_FREQ, band, ¢er); |
| result = android_fx_statusToResult(status); |
| } |
| interface_unlock_shared(thiz); |
| *pCenter = center; |
| #endif |
| } |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetBandFreqRange(SLEqualizerItf self, SLuint16 band, |
| SLmilliHertz *pMin, SLmilliHertz *pMax) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pMin && NULL == pMax) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| if (band >= thiz->mNumBands) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| #if !defined(ANDROID) |
| // Note: no lock, but OK because it is const |
| if (NULL != pMin) |
| *pMin = thiz->mBands[band].mMin; |
| if (NULL != pMax) |
| *pMax = thiz->mBands[band].mMax; |
| result = SL_RESULT_SUCCESS; |
| #else |
| SLmilliHertz range[2] = {0, 0}; // SLmilliHertz is SLuint32 |
| interface_lock_shared(thiz); |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_getParam(thiz->mEqEffect, EQ_PARAM_BAND_FREQ_RANGE, band, range); |
| result = android_fx_statusToResult(status); |
| } |
| interface_unlock_shared(thiz); |
| if (NULL != pMin) { |
| *pMin = range[0]; |
| } |
| if (NULL != pMax) { |
| *pMax = range[1]; |
| } |
| #endif |
| } |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetBand(SLEqualizerItf self, SLmilliHertz frequency, SLuint16 *pBand) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pBand) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| #if !defined(ANDROID) |
| // search for band whose center frequency has the closest ratio to 1.0 |
| // assumes bands are unsorted (a pessimistic assumption) |
| // assumes bands can overlap (a pessimistic assumption) |
| // assumes a small number of bands, so no need for a fancier algorithm |
| const struct EqualizerBand *band; |
| float floatFreq = (float) frequency; |
| float bestRatio = 0.0; |
| SLuint16 bestBand = SL_EQUALIZER_UNDEFINED; |
| for (band = thiz->mBands; band < &thiz->mBands[thiz->mNumBands]; ++band) { |
| if (!(band->mMin <= frequency && frequency <= band->mMax)) |
| continue; |
| assert(band->mMin <= band->mCenter && band->mCenter <= band->mMax); |
| assert(band->mCenter != 0); |
| float ratio = frequency <= band->mCenter ? |
| floatFreq / band->mCenter : band->mCenter / floatFreq; |
| if (ratio > bestRatio) { |
| bestRatio = ratio; |
| bestBand = band - thiz->mBands; |
| } |
| } |
| *pBand = bestBand; |
| result = SL_RESULT_SUCCESS; |
| #else |
| uint16_t band = 0; |
| interface_lock_shared(thiz); |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_getParam(thiz->mEqEffect, EQ_PARAM_GET_BAND, frequency, &band); |
| result = android_fx_statusToResult(status); |
| } |
| interface_unlock_shared(thiz); |
| *pBand = (SLuint16)band; |
| #endif |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetCurrentPreset(SLEqualizerItf self, SLuint16 *pPreset) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pPreset) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| interface_lock_shared(thiz); |
| #if !defined(ANDROID) |
| SLuint16 preset = thiz->mPreset; |
| interface_unlock_shared(thiz); |
| *pPreset = preset; |
| result = SL_RESULT_SUCCESS; |
| #else |
| uint16_t preset = 0; |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_getParam(thiz->mEqEffect, EQ_PARAM_CUR_PRESET, 0, &preset); |
| result = android_fx_statusToResult(status); |
| } |
| interface_unlock_shared(thiz); |
| |
| if (preset < 0) { |
| *pPreset = SL_EQUALIZER_UNDEFINED; |
| } else { |
| *pPreset = (SLuint16) preset; |
| } |
| #endif |
| |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_UsePreset(SLEqualizerItf self, SLuint16 index) |
| { |
| SL_ENTER_INTERFACE |
| SL_LOGV("Equalizer::UsePreset index=%u", index); |
| |
| IEqualizer *thiz = (IEqualizer *) self; |
| if (index >= thiz->mNumPresets) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| interface_lock_exclusive(thiz); |
| #if !defined(ANDROID) |
| SLuint16 band; |
| for (band = 0; band < thiz->mNumBands; ++band) |
| thiz->mLevels[band] = EqualizerPresets[index].mLevels[band]; |
| thiz->mPreset = index; |
| interface_unlock_exclusive(thiz); |
| result = SL_RESULT_SUCCESS; |
| #else |
| if (NO_EQ(thiz)) { |
| result = SL_RESULT_CONTROL_LOST; |
| } else { |
| android::status_t status = |
| android_eq_setParam(thiz->mEqEffect, EQ_PARAM_CUR_PRESET, 0, &index); |
| result = android_fx_statusToResult(status); |
| } |
| interface_unlock_shared(thiz); |
| #endif |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetNumberOfPresets(SLEqualizerItf self, SLuint16 *pNumPresets) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == pNumPresets) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| // Note: no lock, but OK because it is const |
| *pNumPresets = thiz->mNumPresets; |
| |
| result = SL_RESULT_SUCCESS; |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static SLresult IEqualizer_GetPresetName(SLEqualizerItf self, SLuint16 index, const SLchar **ppName) |
| { |
| SL_ENTER_INTERFACE |
| |
| if (NULL == ppName) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| IEqualizer *thiz = (IEqualizer *) self; |
| #if !defined(ANDROID) |
| if (index >= thiz->mNumPresets) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| *ppName = (SLchar *) thiz->mPresets[index].mName; |
| result = SL_RESULT_SUCCESS; |
| } |
| #else |
| if (index >= thiz->mNumPresets) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| // FIXME query preset name rather than retrieve it from the engine. |
| // In SL ES 1.0.1, the strings must exist for the lifetime of the engine. |
| // Starting in 1.1, this will change and we don't need to hold onto the strings |
| // for so long as they will copied into application space. |
| *ppName = (SLchar *) thiz->mThis->mEngine->mEqPresetNames[index]; |
| result = SL_RESULT_SUCCESS; |
| } |
| #endif |
| } |
| |
| SL_LEAVE_INTERFACE |
| } |
| |
| |
| static const struct SLEqualizerItf_ IEqualizer_Itf = { |
| IEqualizer_SetEnabled, |
| IEqualizer_IsEnabled, |
| IEqualizer_GetNumberOfBands, |
| IEqualizer_GetBandLevelRange, |
| IEqualizer_SetBandLevel, |
| IEqualizer_GetBandLevel, |
| IEqualizer_GetCenterFreq, |
| IEqualizer_GetBandFreqRange, |
| IEqualizer_GetBand, |
| IEqualizer_GetCurrentPreset, |
| IEqualizer_UsePreset, |
| IEqualizer_GetNumberOfPresets, |
| IEqualizer_GetPresetName |
| }; |
| |
| void IEqualizer_init(void *self) |
| { |
| IEqualizer *thiz = (IEqualizer *) self; |
| thiz->mItf = &IEqualizer_Itf; |
| thiz->mEnabled = SL_BOOLEAN_FALSE; |
| thiz->mPreset = SL_EQUALIZER_UNDEFINED; |
| #if 0 < MAX_EQ_BANDS |
| unsigned band; |
| for (band = 0; band < MAX_EQ_BANDS; ++band) |
| thiz->mLevels[band] = 0; |
| #endif |
| // const fields |
| thiz->mNumPresets = 0; |
| thiz->mNumBands = 0; |
| #if !defined(ANDROID) |
| thiz->mBands = EqualizerBands; |
| thiz->mPresets = EqualizerPresets; |
| #endif |
| thiz->mBandLevelRangeMin = 0; |
| thiz->mBandLevelRangeMax = 0; |
| #if defined(ANDROID) |
| memset(&thiz->mEqDescriptor, 0, sizeof(effect_descriptor_t)); |
| // placement new (explicit constructor) |
| (void) new (&thiz->mEqEffect) android::sp<android::AudioEffect>(); |
| #endif |
| } |
| |
| void IEqualizer_deinit(void *self) |
| { |
| #if defined(ANDROID) |
| IEqualizer *thiz = (IEqualizer *) self; |
| // explicit destructor |
| thiz->mEqEffect.~sp(); |
| #endif |
| } |
| |
| bool IEqualizer_Expose(void *self) |
| { |
| #if defined(ANDROID) |
| IEqualizer *thiz = (IEqualizer *) self; |
| if (!android_fx_initEffectDescriptor(SL_IID_EQUALIZER, &thiz->mEqDescriptor)) { |
| SL_LOGE("Equalizer initialization failed"); |
| thiz->mNumPresets = 0; |
| thiz->mNumBands = 0; |
| thiz->mBandLevelRangeMin = 0; |
| thiz->mBandLevelRangeMax = 0; |
| return false; |
| } |
| #endif |
| return true; |
| } |