IEqualizer.c revision 87c9a6bbe9dabec3d795675ab0ef74a773cc1670
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/* Equalizer implementation */
18
19#include "sles_allinclusive.h"
20#ifdef ANDROID
21#include "hardware/audio_effect.h"
22#endif
23
24#define MAX_EQ_PRESETS 3
25
26#if !defined(ANDROID)
27static const struct EqualizerBand EqualizerBands[MAX_EQ_BANDS] = {
28    {1000, 1500, 2000},
29    {2000, 3000, 4000},
30    {4000, 5500, 7000},
31    {7000, 8000, 9000}
32};
33
34static const struct EqualizerPreset {
35    const char *mName;
36    SLmillibel mLevels[MAX_EQ_BANDS];
37} EqualizerPresets[MAX_EQ_PRESETS] = {
38    {"Default", {0, 0, 0, 0}},
39    {"Bass", {500, 200, 100, 0}},
40    {"Treble", {0, 100, 200, 500}}
41};
42#endif
43
44
45#if defined(ANDROID)
46/**
47 * returns true if this interface is not associated with an initialized Equalizer effect
48 */
49static inline bool NO_EQ(IEqualizer* v) {
50    return (v->mEqEffect == 0);
51}
52#endif
53
54
55static SLresult IEqualizer_SetEnabled(SLEqualizerItf self, SLboolean enabled)
56{
57    SL_ENTER_INTERFACE
58
59    IEqualizer *thiz = (IEqualizer *) self;
60    interface_lock_exclusive(thiz);
61    thiz->mEnabled = (SLboolean) enabled;
62#if !defined(ANDROID)
63    result = SL_RESULT_SUCCESS;
64#else
65    if (NO_EQ(thiz)) {
66        result = SL_RESULT_CONTROL_LOST;
67    } else {
68        android::status_t status =
69                thiz->mEqEffect->setEnabled((bool) thiz->mEnabled);
70        result = android_fx_statusToResult(status);
71    }
72#endif
73    interface_unlock_exclusive(thiz);
74
75    SL_LEAVE_INTERFACE
76}
77
78
79static SLresult IEqualizer_IsEnabled(SLEqualizerItf self, SLboolean *pEnabled)
80{
81    SL_ENTER_INTERFACE
82
83      if (NULL == pEnabled) {
84          result = SL_RESULT_PARAMETER_INVALID;
85      } else {
86          IEqualizer *thiz = (IEqualizer *) self;
87          interface_lock_exclusive(thiz);
88          SLboolean enabled = thiz->mEnabled;
89 #if !defined(ANDROID)
90          *pEnabled = enabled;
91          result = SL_RESULT_SUCCESS;
92 #else
93          if (NO_EQ(thiz)) {
94              result = SL_RESULT_CONTROL_LOST;
95          } else {
96              *pEnabled = (SLboolean) thiz->mEqEffect->getEnabled();
97              result = SL_RESULT_SUCCESS;
98          }
99 #endif
100          interface_unlock_exclusive(thiz);
101      }
102
103      SL_LEAVE_INTERFACE
104}
105
106
107static SLresult IEqualizer_GetNumberOfBands(SLEqualizerItf self, SLuint16 *pNumBands)
108{
109    SL_ENTER_INTERFACE
110
111    if (NULL == pNumBands) {
112        result = SL_RESULT_PARAMETER_INVALID;
113    } else {
114        IEqualizer *thiz = (IEqualizer *) self;
115        // Note: no lock, but OK because it is const
116        *pNumBands = thiz->mNumBands;
117        result = SL_RESULT_SUCCESS;
118    }
119
120    SL_LEAVE_INTERFACE
121}
122
123
124static SLresult IEqualizer_GetBandLevelRange(SLEqualizerItf self, SLmillibel *pMin,
125    SLmillibel *pMax)
126{
127    SL_ENTER_INTERFACE
128
129    if (NULL == pMin && NULL == pMax) {
130        result = SL_RESULT_PARAMETER_INVALID;
131    } else {
132        IEqualizer *thiz = (IEqualizer *) self;
133        // Note: no lock, but OK because it is const
134        if (NULL != pMin)
135            *pMin = thiz->mBandLevelRangeMin;
136        if (NULL != pMax)
137            *pMax = thiz->mBandLevelRangeMax;
138        result = SL_RESULT_SUCCESS;
139    }
140
141    SL_LEAVE_INTERFACE
142}
143
144
145static SLresult IEqualizer_SetBandLevel(SLEqualizerItf self, SLuint16 band, SLmillibel level)
146{
147    SL_ENTER_INTERFACE
148
149    IEqualizer *thiz = (IEqualizer *) self;
150    if (!(thiz->mBandLevelRangeMin <= level && level <= thiz->mBandLevelRangeMax) ||
151            (band >= thiz->mNumBands)) {
152        result = SL_RESULT_PARAMETER_INVALID;
153    } else {
154        interface_lock_exclusive(thiz);
155#if !defined(ANDROID)
156        thiz->mLevels[band] = level;
157        thiz->mPreset = SL_EQUALIZER_UNDEFINED;
158        result = SL_RESULT_SUCCESS;
159#else
160        if (NO_EQ(thiz)) {
161            result = SL_RESULT_CONTROL_LOST;
162        } else {
163            android::status_t status =
164                android_eq_setParam(thiz->mEqEffect, EQ_PARAM_BAND_LEVEL, band, &level);
165            result = android_fx_statusToResult(status);
166        }
167#endif
168        interface_unlock_exclusive(thiz);
169    }
170
171    SL_LEAVE_INTERFACE
172}
173
174
175static SLresult IEqualizer_GetBandLevel(SLEqualizerItf self, SLuint16 band, SLmillibel *pLevel)
176{
177    SL_ENTER_INTERFACE
178
179    if (NULL == pLevel) {
180        result = SL_RESULT_PARAMETER_INVALID;
181    } else {
182        IEqualizer *thiz = (IEqualizer *) self;
183        // const, no lock needed
184        if (band >= thiz->mNumBands) {
185            result = SL_RESULT_PARAMETER_INVALID;
186        } else {
187            SLmillibel level = 0;
188            interface_lock_shared(thiz);
189#if !defined(ANDROID)
190            level = thiz->mLevels[band];
191            result = SL_RESULT_SUCCESS;
192#else
193            if (NO_EQ(thiz)) {
194                result = SL_RESULT_CONTROL_LOST;
195            } else {
196                android::status_t status =
197                    android_eq_getParam(thiz->mEqEffect, EQ_PARAM_BAND_LEVEL, band, &level);
198                result = android_fx_statusToResult(status);
199            }
200#endif
201            interface_unlock_shared(thiz);
202            *pLevel = level;
203        }
204    }
205
206    SL_LEAVE_INTERFACE
207}
208
209
210static SLresult IEqualizer_GetCenterFreq(SLEqualizerItf self, SLuint16 band, SLmilliHertz *pCenter)
211{
212    SL_ENTER_INTERFACE
213
214    if (NULL == pCenter) {
215        result = SL_RESULT_PARAMETER_INVALID;
216    } else {
217        IEqualizer *thiz = (IEqualizer *) self;
218        if (band >= thiz->mNumBands) {
219            result = SL_RESULT_PARAMETER_INVALID;
220        } else {
221#if !defined(ANDROID)
222            // Note: no lock, but OK because it is const
223            *pCenter = thiz->mBands[band].mCenter;
224            result = SL_RESULT_SUCCESS;
225#else
226            SLmilliHertz center = 0;
227            interface_lock_shared(thiz);
228            if (NO_EQ(thiz)) {
229                result = SL_RESULT_CONTROL_LOST;
230            } else {
231                android::status_t status =
232                    android_eq_getParam(thiz->mEqEffect, EQ_PARAM_CENTER_FREQ, band, &center);
233                result = android_fx_statusToResult(status);
234            }
235            interface_unlock_shared(thiz);
236            *pCenter = center;
237#endif
238        }
239    }
240
241    SL_LEAVE_INTERFACE
242}
243
244
245static SLresult IEqualizer_GetBandFreqRange(SLEqualizerItf self, SLuint16 band,
246    SLmilliHertz *pMin, SLmilliHertz *pMax)
247{
248    SL_ENTER_INTERFACE
249
250    if (NULL == pMin && NULL == pMax) {
251        result = SL_RESULT_PARAMETER_INVALID;
252    } else {
253        IEqualizer *thiz = (IEqualizer *) self;
254        if (band >= thiz->mNumBands) {
255            result = SL_RESULT_PARAMETER_INVALID;
256        } else {
257#if !defined(ANDROID)
258            // Note: no lock, but OK because it is const
259            if (NULL != pMin)
260                *pMin = thiz->mBands[band].mMin;
261            if (NULL != pMax)
262                *pMax = thiz->mBands[band].mMax;
263            result = SL_RESULT_SUCCESS;
264#else
265            SLmilliHertz range[2] = {0, 0}; // SLmilliHertz is SLuint32
266            interface_lock_shared(thiz);
267            if (NO_EQ(thiz)) {
268                result = SL_RESULT_CONTROL_LOST;
269            } else {
270                android::status_t status =
271                    android_eq_getParam(thiz->mEqEffect, EQ_PARAM_BAND_FREQ_RANGE, band, range);
272                result = android_fx_statusToResult(status);
273            }
274            interface_unlock_shared(thiz);
275            if (NULL != pMin) {
276                *pMin = range[0];
277            }
278            if (NULL != pMax) {
279                *pMax = range[1];
280            }
281#endif
282        }
283    }
284
285    SL_LEAVE_INTERFACE
286}
287
288
289static SLresult IEqualizer_GetBand(SLEqualizerItf self, SLmilliHertz frequency, SLuint16 *pBand)
290{
291    SL_ENTER_INTERFACE
292
293    if (NULL == pBand) {
294        result = SL_RESULT_PARAMETER_INVALID;
295    } else {
296        IEqualizer *thiz = (IEqualizer *) self;
297#if !defined(ANDROID)
298        // search for band whose center frequency has the closest ratio to 1.0
299        // assumes bands are unsorted (a pessimistic assumption)
300        // assumes bands can overlap (a pessimistic assumption)
301        // assumes a small number of bands, so no need for a fancier algorithm
302        const struct EqualizerBand *band;
303        float floatFreq = (float) frequency;
304        float bestRatio = 0.0;
305        SLuint16 bestBand = SL_EQUALIZER_UNDEFINED;
306        for (band = thiz->mBands; band < &thiz->mBands[thiz->mNumBands]; ++band) {
307            if (!(band->mMin <= frequency && frequency <= band->mMax))
308                continue;
309            assert(band->mMin <= band->mCenter && band->mCenter <= band->mMax);
310            assert(band->mCenter != 0);
311            float ratio = frequency <= band->mCenter ?
312                floatFreq / band->mCenter : band->mCenter / floatFreq;
313            if (ratio > bestRatio) {
314                bestRatio = ratio;
315                bestBand = band - thiz->mBands;
316            }
317        }
318        *pBand = bestBand;
319        result = SL_RESULT_SUCCESS;
320#else
321        uint16_t band = 0;
322        interface_lock_shared(thiz);
323        if (NO_EQ(thiz)) {
324            result = SL_RESULT_CONTROL_LOST;
325        } else {
326            android::status_t status =
327                android_eq_getParam(thiz->mEqEffect, EQ_PARAM_GET_BAND, frequency, &band);
328            result = android_fx_statusToResult(status);
329        }
330        interface_unlock_shared(thiz);
331        *pBand = (SLuint16)band;
332#endif
333    }
334
335    SL_LEAVE_INTERFACE
336}
337
338
339static SLresult IEqualizer_GetCurrentPreset(SLEqualizerItf self, SLuint16 *pPreset)
340{
341    SL_ENTER_INTERFACE
342
343    if (NULL == pPreset) {
344        result = SL_RESULT_PARAMETER_INVALID;
345    } else {
346        IEqualizer *thiz = (IEqualizer *) self;
347        interface_lock_shared(thiz);
348#if !defined(ANDROID)
349        SLuint16 preset = thiz->mPreset;
350        interface_unlock_shared(thiz);
351        *pPreset = preset;
352        result = SL_RESULT_SUCCESS;
353#else
354        uint16_t preset = 0;
355        if (NO_EQ(thiz)) {
356            result = SL_RESULT_CONTROL_LOST;
357        } else {
358            android::status_t status =
359                    android_eq_getParam(thiz->mEqEffect, EQ_PARAM_CUR_PRESET, 0, &preset);
360            result = android_fx_statusToResult(status);
361        }
362        interface_unlock_shared(thiz);
363
364        if (preset < 0) {
365            *pPreset = SL_EQUALIZER_UNDEFINED;
366        } else {
367            *pPreset = (SLuint16) preset;
368        }
369#endif
370
371    }
372
373    SL_LEAVE_INTERFACE
374}
375
376
377static SLresult IEqualizer_UsePreset(SLEqualizerItf self, SLuint16 index)
378{
379    SL_ENTER_INTERFACE
380    SL_LOGV("Equalizer::UsePreset index=%u", index);
381
382    IEqualizer *thiz = (IEqualizer *) self;
383    if (index >= thiz->mNumPresets) {
384        result = SL_RESULT_PARAMETER_INVALID;
385    } else {
386        interface_lock_exclusive(thiz);
387#if !defined(ANDROID)
388        SLuint16 band;
389        for (band = 0; band < thiz->mNumBands; ++band)
390            thiz->mLevels[band] = EqualizerPresets[index].mLevels[band];
391        thiz->mPreset = index;
392        interface_unlock_exclusive(thiz);
393        result = SL_RESULT_SUCCESS;
394#else
395        if (NO_EQ(thiz)) {
396            result = SL_RESULT_CONTROL_LOST;
397        } else {
398            android::status_t status =
399                android_eq_setParam(thiz->mEqEffect, EQ_PARAM_CUR_PRESET, 0, &index);
400            result = android_fx_statusToResult(status);
401        }
402        interface_unlock_shared(thiz);
403#endif
404    }
405
406    SL_LEAVE_INTERFACE
407}
408
409
410static SLresult IEqualizer_GetNumberOfPresets(SLEqualizerItf self, SLuint16 *pNumPresets)
411{
412    SL_ENTER_INTERFACE
413
414    if (NULL == pNumPresets) {
415        result = SL_RESULT_PARAMETER_INVALID;
416    } else {
417        IEqualizer *thiz = (IEqualizer *) self;
418        // Note: no lock, but OK because it is const
419        *pNumPresets = thiz->mNumPresets;
420
421        result = SL_RESULT_SUCCESS;
422    }
423
424    SL_LEAVE_INTERFACE
425}
426
427
428static SLresult IEqualizer_GetPresetName(SLEqualizerItf self, SLuint16 index, const SLchar **ppName)
429{
430    SL_ENTER_INTERFACE
431
432    if (NULL == ppName) {
433        result = SL_RESULT_PARAMETER_INVALID;
434    } else {
435        IEqualizer *thiz = (IEqualizer *) self;
436#if !defined(ANDROID)
437        if (index >= thiz->mNumPresets) {
438            result = SL_RESULT_PARAMETER_INVALID;
439        } else {
440            *ppName = (SLchar *) thiz->mPresets[index].mName;
441            result = SL_RESULT_SUCCESS;
442        }
443#else
444        if (index >= thiz->mNumPresets) {
445            result = SL_RESULT_PARAMETER_INVALID;
446        } else {
447            // FIXME query preset name rather than retrieve it from the engine.
448            //       In SL ES 1.0.1, the strings must exist for the lifetime of the engine.
449            //       Starting in 1.1, this will change and we don't need to hold onto the strings
450            //       for so long as they will copied into application space.
451            *ppName = (SLchar *) thiz->mThis->mEngine->mEqPresetNames[index];
452            result = SL_RESULT_SUCCESS;
453        }
454#endif
455    }
456
457    SL_LEAVE_INTERFACE
458}
459
460
461static const struct SLEqualizerItf_ IEqualizer_Itf = {
462    IEqualizer_SetEnabled,
463    IEqualizer_IsEnabled,
464    IEqualizer_GetNumberOfBands,
465    IEqualizer_GetBandLevelRange,
466    IEqualizer_SetBandLevel,
467    IEqualizer_GetBandLevel,
468    IEqualizer_GetCenterFreq,
469    IEqualizer_GetBandFreqRange,
470    IEqualizer_GetBand,
471    IEqualizer_GetCurrentPreset,
472    IEqualizer_UsePreset,
473    IEqualizer_GetNumberOfPresets,
474    IEqualizer_GetPresetName
475};
476
477void IEqualizer_init(void *self)
478{
479    IEqualizer *thiz = (IEqualizer *) self;
480    thiz->mItf = &IEqualizer_Itf;
481    thiz->mEnabled = SL_BOOLEAN_FALSE;
482    thiz->mPreset = SL_EQUALIZER_UNDEFINED;
483#if 0 < MAX_EQ_BANDS
484    unsigned band;
485    for (band = 0; band < MAX_EQ_BANDS; ++band)
486        thiz->mLevels[band] = 0;
487#endif
488    // const fields
489    thiz->mNumPresets = 0;
490    thiz->mNumBands = 0;
491#if !defined(ANDROID)
492    thiz->mBands = EqualizerBands;
493    thiz->mPresets = EqualizerPresets;
494#endif
495    thiz->mBandLevelRangeMin = 0;
496    thiz->mBandLevelRangeMax = 0;
497#if defined(ANDROID)
498    memset(&thiz->mEqDescriptor, 0, sizeof(effect_descriptor_t));
499    // placement new (explicit constructor)
500    (void) new (&thiz->mEqEffect) android::sp<android::AudioEffect>();
501#endif
502}
503
504void IEqualizer_deinit(void *self)
505{
506#if defined(ANDROID)
507    IEqualizer *thiz = (IEqualizer *) self;
508    // explicit destructor
509    thiz->mEqEffect.~sp();
510#endif
511}
512
513bool IEqualizer_Expose(void *self)
514{
515#if defined(ANDROID)
516    IEqualizer *thiz = (IEqualizer *) self;
517    if (!android_fx_initEffectDescriptor(SL_IID_EQUALIZER, &thiz->mEqDescriptor)) {
518        SL_LOGE("Equalizer initialization failed");
519        thiz->mNumPresets = 0;
520        thiz->mNumBands = 0;
521        thiz->mBandLevelRangeMin = 0;
522        thiz->mBandLevelRangeMax = 0;
523        return false;
524    }
525#endif
526    return true;
527}
528