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