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 <audio_effects/effect_equalizer.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 #if !defined(ANDROID)
89        SLboolean enabled = thiz->mEnabled;
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        *pPreset = (SLuint16) preset;
365#endif
366
367    }
368
369    SL_LEAVE_INTERFACE
370}
371
372
373static SLresult IEqualizer_UsePreset(SLEqualizerItf self, SLuint16 index)
374{
375    SL_ENTER_INTERFACE
376    SL_LOGV("Equalizer::UsePreset index=%u", index);
377
378    IEqualizer *thiz = (IEqualizer *) self;
379    if (index >= thiz->mNumPresets) {
380        result = SL_RESULT_PARAMETER_INVALID;
381    } else {
382        interface_lock_exclusive(thiz);
383#if !defined(ANDROID)
384        SLuint16 band;
385        for (band = 0; band < thiz->mNumBands; ++band)
386            thiz->mLevels[band] = EqualizerPresets[index].mLevels[band];
387        thiz->mPreset = index;
388        interface_unlock_exclusive(thiz);
389        result = SL_RESULT_SUCCESS;
390#else
391        if (NO_EQ(thiz)) {
392            result = SL_RESULT_CONTROL_LOST;
393        } else {
394            android::status_t status =
395                android_eq_setParam(thiz->mEqEffect, EQ_PARAM_CUR_PRESET, 0, &index);
396            result = android_fx_statusToResult(status);
397        }
398        interface_unlock_shared(thiz);
399#endif
400    }
401
402    SL_LEAVE_INTERFACE
403}
404
405
406static SLresult IEqualizer_GetNumberOfPresets(SLEqualizerItf self, SLuint16 *pNumPresets)
407{
408    SL_ENTER_INTERFACE
409
410    if (NULL == pNumPresets) {
411        result = SL_RESULT_PARAMETER_INVALID;
412    } else {
413        IEqualizer *thiz = (IEqualizer *) self;
414        // Note: no lock, but OK because it is const
415        *pNumPresets = thiz->mNumPresets;
416
417        result = SL_RESULT_SUCCESS;
418    }
419
420    SL_LEAVE_INTERFACE
421}
422
423
424static SLresult IEqualizer_GetPresetName(SLEqualizerItf self, SLuint16 index, const SLchar **ppName)
425{
426    SL_ENTER_INTERFACE
427
428    if (NULL == ppName) {
429        result = SL_RESULT_PARAMETER_INVALID;
430    } else {
431        IEqualizer *thiz = (IEqualizer *) self;
432#if !defined(ANDROID)
433        if (index >= thiz->mNumPresets) {
434            result = SL_RESULT_PARAMETER_INVALID;
435        } else {
436            *ppName = (SLchar *) thiz->mPresets[index].mName;
437            result = SL_RESULT_SUCCESS;
438        }
439#else
440        if (index >= thiz->mNumPresets) {
441            result = SL_RESULT_PARAMETER_INVALID;
442        } else {
443            // FIXME query preset name rather than retrieve it from the engine.
444            //       In SL ES 1.0.1, the strings must exist for the lifetime of the engine.
445            //       Starting in 1.1, this will change and we don't need to hold onto the strings
446            //       for so long as they will copied into application space.
447            *ppName = (SLchar *) thiz->mThis->mEngine->mEqPresetNames[index];
448            result = SL_RESULT_SUCCESS;
449        }
450#endif
451    }
452
453    SL_LEAVE_INTERFACE
454}
455
456
457static const struct SLEqualizerItf_ IEqualizer_Itf = {
458    IEqualizer_SetEnabled,
459    IEqualizer_IsEnabled,
460    IEqualizer_GetNumberOfBands,
461    IEqualizer_GetBandLevelRange,
462    IEqualizer_SetBandLevel,
463    IEqualizer_GetBandLevel,
464    IEqualizer_GetCenterFreq,
465    IEqualizer_GetBandFreqRange,
466    IEqualizer_GetBand,
467    IEqualizer_GetCurrentPreset,
468    IEqualizer_UsePreset,
469    IEqualizer_GetNumberOfPresets,
470    IEqualizer_GetPresetName
471};
472
473void IEqualizer_init(void *self)
474{
475    IEqualizer *thiz = (IEqualizer *) self;
476    thiz->mItf = &IEqualizer_Itf;
477    thiz->mEnabled = SL_BOOLEAN_FALSE;
478    thiz->mPreset = SL_EQUALIZER_UNDEFINED;
479#if 0 < MAX_EQ_BANDS
480    unsigned band;
481    for (band = 0; band < MAX_EQ_BANDS; ++band)
482        thiz->mLevels[band] = 0;
483#endif
484    // const fields
485    thiz->mNumPresets = 0;
486    thiz->mNumBands = 0;
487#if !defined(ANDROID)
488    thiz->mBands = EqualizerBands;
489    thiz->mPresets = EqualizerPresets;
490#endif
491    thiz->mBandLevelRangeMin = 0;
492    thiz->mBandLevelRangeMax = 0;
493#if defined(ANDROID)
494    memset(&thiz->mEqDescriptor, 0, sizeof(effect_descriptor_t));
495    // placement new (explicit constructor)
496    (void) new (&thiz->mEqEffect) android::sp<android::AudioEffect>();
497#endif
498}
499
500void IEqualizer_deinit(void *self)
501{
502#if defined(ANDROID)
503    IEqualizer *thiz = (IEqualizer *) self;
504    // explicit destructor
505    thiz->mEqEffect.~sp();
506#endif
507}
508
509bool IEqualizer_Expose(void *self)
510{
511#if defined(ANDROID)
512    IEqualizer *thiz = (IEqualizer *) self;
513    if (!android_fx_initEffectDescriptor(SL_IID_EQUALIZER, &thiz->mEqDescriptor)) {
514        SL_LOGE("Equalizer initialization failed");
515        thiz->mNumPresets = 0;
516        thiz->mNumBands = 0;
517        thiz->mBandLevelRangeMin = 0;
518        thiz->mBandLevelRangeMax = 0;
519        return false;
520    }
521#endif
522    return true;
523}
524