/* * Copyright (C) 2009 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. */ #define LOG_TAG "Equalizer" #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) // #define LOG_NDEBUG 0 #include #include #include #include #include #include "AudioEqualizer.h" #include "AudioBiquadFilter.h" #include "AudioFormatAdapter.h" #include // effect_handle_t interface implementation for equalizer effect extern "C" const struct effect_interface_s gEqualizerInterface; enum equalizer_state_e { EQUALIZER_STATE_UNINITIALIZED, EQUALIZER_STATE_INITIALIZED, EQUALIZER_STATE_ACTIVE, }; namespace android { namespace { // Google Graphic Equalizer UUID: e25aa840-543b-11df-98a5-0002a5d5c51b const effect_descriptor_t gEqualizerDescriptor = { {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type {0xe25aa840, 0x543b, 0x11df, 0x98a5, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid EFFECT_CONTROL_API_VERSION, (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST), 0, // TODO 1, "Graphic Equalizer", "The Android Open Source Project", }; /////////////////// BEGIN EQ PRESETS /////////////////////////////////////////// const int kNumBands = 5; const uint32_t gFreqs[kNumBands] = { 50000, 125000, 900000, 3200000, 6300000 }; const uint32_t gBandwidths[kNumBands] = { 0, 3600, 3600, 2400, 0 }; const AudioEqualizer::BandConfig gBandsClassic[kNumBands] = { { 300, gFreqs[0], gBandwidths[0] }, { 400, gFreqs[1], gBandwidths[1] }, { 0, gFreqs[2], gBandwidths[2] }, { 200, gFreqs[3], gBandwidths[3] }, { -300, gFreqs[4], gBandwidths[4] } }; const AudioEqualizer::BandConfig gBandsJazz[kNumBands] = { { -600, gFreqs[0], gBandwidths[0] }, { 200, gFreqs[1], gBandwidths[1] }, { 400, gFreqs[2], gBandwidths[2] }, { -400, gFreqs[3], gBandwidths[3] }, { -600, gFreqs[4], gBandwidths[4] } }; const AudioEqualizer::BandConfig gBandsPop[kNumBands] = { { 400, gFreqs[0], gBandwidths[0] }, { -400, gFreqs[1], gBandwidths[1] }, { 300, gFreqs[2], gBandwidths[2] }, { -400, gFreqs[3], gBandwidths[3] }, { 600, gFreqs[4], gBandwidths[4] } }; const AudioEqualizer::BandConfig gBandsRock[kNumBands] = { { 700, gFreqs[0], gBandwidths[0] }, { 400, gFreqs[1], gBandwidths[1] }, { -400, gFreqs[2], gBandwidths[2] }, { 400, gFreqs[3], gBandwidths[3] }, { 200, gFreqs[4], gBandwidths[4] } }; const AudioEqualizer::PresetConfig gEqualizerPresets[] = { { "Classic", gBandsClassic }, { "Jazz", gBandsJazz }, { "Pop", gBandsPop }, { "Rock", gBandsRock } }; /////////////////// END EQ PRESETS ///////////////////////////////////////////// static const size_t kBufferSize = 32; typedef AudioFormatAdapter FormatAdapter; struct EqualizerContext { const struct effect_interface_s *itfe; effect_config_t config; FormatAdapter adapter; AudioEqualizer * pEqualizer; uint32_t state; }; //--- local function prototypes int Equalizer_init(EqualizerContext *pContext); int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig); int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, uint32_t *pValueSize, void *pValue); int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue); // //--- Effect Library Interface Implementation // extern "C" int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle) { int ret; int i; ALOGV("EffectLibCreateEffect start"); if (pHandle == NULL || uuid == NULL) { return -EINVAL; } if (memcmp(uuid, &gEqualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) { return -EINVAL; } EqualizerContext *pContext = new EqualizerContext; pContext->itfe = &gEqualizerInterface; pContext->pEqualizer = NULL; pContext->state = EQUALIZER_STATE_UNINITIALIZED; ret = Equalizer_init(pContext); if (ret < 0) { ALOGW("EffectLibCreateEffect() init failed"); delete pContext; return ret; } *pHandle = (effect_handle_t)pContext; pContext->state = EQUALIZER_STATE_INITIALIZED; ALOGV("EffectLibCreateEffect %p, size %d", pContext, AudioEqualizer::GetInstanceSize(kNumBands)+sizeof(EqualizerContext)); return 0; } /* end EffectCreate */ extern "C" int EffectRelease(effect_handle_t handle) { EqualizerContext * pContext = (EqualizerContext *)handle; ALOGV("EffectLibReleaseEffect %p", handle); if (pContext == NULL) { return -EINVAL; } pContext->state = EQUALIZER_STATE_UNINITIALIZED; pContext->pEqualizer->free(); delete pContext; return 0; } /* end EffectRelease */ extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) { if (pDescriptor == NULL || uuid == NULL){ ALOGV("EffectGetDescriptor() called with NULL pointer"); return -EINVAL; } if (memcmp(uuid, &gEqualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) { *pDescriptor = gEqualizerDescriptor; return 0; } return -EINVAL; } /* end EffectGetDescriptor */ // //--- local functions // #define CHECK_ARG(cond) { \ if (!(cond)) { \ ALOGV("Invalid argument: "#cond); \ return -EINVAL; \ } \ } //---------------------------------------------------------------------------- // Equalizer_setConfig() //---------------------------------------------------------------------------- // Purpose: Set input and output audio configuration. // // Inputs: // pContext: effect engine context // pConfig: pointer to effect_config_t structure holding input and output // configuration parameters // // Outputs: // //---------------------------------------------------------------------------- int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig) { ALOGV("Equalizer_setConfig start"); CHECK_ARG(pContext != NULL); CHECK_ARG(pConfig != NULL); CHECK_ARG(pConfig->inputCfg.samplingRate == pConfig->outputCfg.samplingRate); CHECK_ARG(pConfig->inputCfg.channels == pConfig->outputCfg.channels); CHECK_ARG(pConfig->inputCfg.format == pConfig->outputCfg.format); CHECK_ARG((pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) || (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO)); CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE); CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT); int channelCount; if (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) { channelCount = 1; } else { channelCount = 2; } CHECK_ARG(channelCount <= AudioBiquadFilter::MAX_CHANNELS); pContext->config = *pConfig; pContext->pEqualizer->configure(channelCount, pConfig->inputCfg.samplingRate); pContext->adapter.configure(*pContext->pEqualizer, channelCount, pConfig->inputCfg.format, pConfig->outputCfg.accessMode); return 0; } // end Equalizer_setConfig //---------------------------------------------------------------------------- // Equalizer_getConfig() //---------------------------------------------------------------------------- // Purpose: Get input and output audio configuration. // // Inputs: // pContext: effect engine context // pConfig: pointer to effect_config_t structure holding input and output // configuration parameters // // Outputs: // //---------------------------------------------------------------------------- void Equalizer_getConfig(EqualizerContext *pContext, effect_config_t *pConfig) { *pConfig = pContext->config; } // end Equalizer_getConfig //---------------------------------------------------------------------------- // Equalizer_init() //---------------------------------------------------------------------------- // Purpose: Initialize engine with default configuration and creates // AudioEqualizer instance. // // Inputs: // pContext: effect engine context // // Outputs: // //---------------------------------------------------------------------------- int Equalizer_init(EqualizerContext *pContext) { int status; ALOGV("Equalizer_init start"); CHECK_ARG(pContext != NULL); if (pContext->pEqualizer != NULL) { pContext->pEqualizer->free(); } pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; pContext->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; pContext->config.inputCfg.samplingRate = 44100; pContext->config.inputCfg.bufferProvider.getBuffer = NULL; pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL; pContext->config.inputCfg.bufferProvider.cookie = NULL; pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL; pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; pContext->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; pContext->config.outputCfg.samplingRate = 44100; pContext->config.outputCfg.bufferProvider.getBuffer = NULL; pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL; pContext->config.outputCfg.bufferProvider.cookie = NULL; pContext->config.outputCfg.mask = EFFECT_CONFIG_ALL; pContext->pEqualizer = AudioEqualizer::CreateInstance( NULL, kNumBands, AudioBiquadFilter::MAX_CHANNELS, 44100, gEqualizerPresets, ARRAY_SIZE(gEqualizerPresets)); for (int i = 0; i < kNumBands; ++i) { pContext->pEqualizer->setFrequency(i, gFreqs[i]); pContext->pEqualizer->setBandwidth(i, gBandwidths[i]); } pContext->pEqualizer->enable(true); Equalizer_setConfig(pContext, &pContext->config); return 0; } // end Equalizer_init //---------------------------------------------------------------------------- // Equalizer_getParameter() //---------------------------------------------------------------------------- // Purpose: // Get a Equalizer parameter // // Inputs: // pEqualizer - handle to instance data // pParam - pointer to parameter // pValue - pointer to variable to hold retrieved value // pValueSize - pointer to value size: maximum size as input // // Outputs: // *pValue updated with parameter value // *pValueSize updated with actual value size // // // Side Effects: // //---------------------------------------------------------------------------- int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, uint32_t *pValueSize, void *pValue) { int status = 0; int32_t param = *pParam++; int32_t param2; char *name; switch (param) { case EQ_PARAM_NUM_BANDS: case EQ_PARAM_CUR_PRESET: case EQ_PARAM_GET_NUM_OF_PRESETS: case EQ_PARAM_BAND_LEVEL: case EQ_PARAM_GET_BAND: if (*pValueSize < sizeof(int16_t)) { return -EINVAL; } *pValueSize = sizeof(int16_t); break; case EQ_PARAM_LEVEL_RANGE: if (*pValueSize < 2 * sizeof(int16_t)) { return -EINVAL; } *pValueSize = 2 * sizeof(int16_t); break; case EQ_PARAM_BAND_FREQ_RANGE: if (*pValueSize < 2 * sizeof(int32_t)) { return -EINVAL; } *pValueSize = 2 * sizeof(int32_t); break; case EQ_PARAM_CENTER_FREQ: if (*pValueSize < sizeof(int32_t)) { return -EINVAL; } *pValueSize = sizeof(int32_t); break; case EQ_PARAM_GET_PRESET_NAME: break; case EQ_PARAM_PROPERTIES: if (*pValueSize < (2 + kNumBands) * sizeof(uint16_t)) { return -EINVAL; } *pValueSize = (2 + kNumBands) * sizeof(uint16_t); break; default: return -EINVAL; } switch (param) { case EQ_PARAM_NUM_BANDS: *(uint16_t *)pValue = (uint16_t)kNumBands; ALOGV("Equalizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue); break; case EQ_PARAM_LEVEL_RANGE: *(int16_t *)pValue = -9600; *((int16_t *)pValue + 1) = 4800; ALOGV("Equalizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d", *(int32_t *)pValue, *((int32_t *)pValue + 1)); break; case EQ_PARAM_BAND_LEVEL: param2 = *pParam; if (param2 >= kNumBands) { status = -EINVAL; break; } *(int16_t *)pValue = (int16_t)pEqualizer->getGain(param2); ALOGV("Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", param2, *(int32_t *)pValue); break; case EQ_PARAM_CENTER_FREQ: param2 = *pParam; if (param2 >= kNumBands) { status = -EINVAL; break; } *(int32_t *)pValue = pEqualizer->getFrequency(param2); ALOGV("Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d", param2, *(int32_t *)pValue); break; case EQ_PARAM_BAND_FREQ_RANGE: param2 = *pParam; if (param2 >= kNumBands) { status = -EINVAL; break; } pEqualizer->getBandRange(param2, *(uint32_t *)pValue, *((uint32_t *)pValue + 1)); ALOGV("Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d", param2, *(int32_t *)pValue, *((int32_t *)pValue + 1)); break; case EQ_PARAM_GET_BAND: param2 = *pParam; *(uint16_t *)pValue = (uint16_t)pEqualizer->getMostRelevantBand(param2); ALOGV("Equalizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d", param2, *(int32_t *)pValue); break; case EQ_PARAM_CUR_PRESET: *(uint16_t *)pValue = (uint16_t)pEqualizer->getPreset(); ALOGV("Equalizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue); break; case EQ_PARAM_GET_NUM_OF_PRESETS: *(uint16_t *)pValue = (uint16_t)pEqualizer->getNumPresets(); ALOGV("Equalizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue); break; case EQ_PARAM_GET_PRESET_NAME: param2 = *pParam; if (param2 >= pEqualizer->getNumPresets()) { status = -EINVAL; break; } name = (char *)pValue; strncpy(name, pEqualizer->getPresetName(param2), *pValueSize - 1); name[*pValueSize - 1] = 0; *pValueSize = strlen(name) + 1; ALOGV("Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d", param2, gEqualizerPresets[param2].name, *pValueSize); break; case EQ_PARAM_PROPERTIES: { int16_t *p = (int16_t *)pValue; ALOGV("Equalizer_getParameter() EQ_PARAM_PROPERTIES"); p[0] = (int16_t)pEqualizer->getPreset(); p[1] = (int16_t)kNumBands; for (int i = 0; i < kNumBands; i++) { p[2 + i] = (int16_t)pEqualizer->getGain(i); } } break; default: ALOGV("Equalizer_getParameter() invalid param %d", param); status = -EINVAL; break; } return status; } // end Equalizer_getParameter //---------------------------------------------------------------------------- // Equalizer_setParameter() //---------------------------------------------------------------------------- // Purpose: // Set a Equalizer parameter // // Inputs: // pEqualizer - handle to instance data // pParam - pointer to parameter // pValue - pointer to value // // Outputs: // // // Side Effects: // //---------------------------------------------------------------------------- int Equalizer_setParameter (AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue) { int status = 0; int32_t preset; int32_t band; int32_t level; int32_t param = *pParam++; switch (param) { case EQ_PARAM_CUR_PRESET: preset = (int32_t)(*(uint16_t *)pValue); ALOGV("setParameter() EQ_PARAM_CUR_PRESET %d", preset); if (preset < 0 || preset >= pEqualizer->getNumPresets()) { status = -EINVAL; break; } pEqualizer->setPreset(preset); pEqualizer->commit(true); break; case EQ_PARAM_BAND_LEVEL: band = *pParam; level = (int32_t)(*(int16_t *)pValue); ALOGV("setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level); if (band >= kNumBands) { status = -EINVAL; break; } pEqualizer->setGain(band, level); pEqualizer->commit(true); break; case EQ_PARAM_PROPERTIES: { ALOGV("setParameter() EQ_PARAM_PROPERTIES"); int16_t *p = (int16_t *)pValue; if ((int)p[0] >= pEqualizer->getNumPresets()) { status = -EINVAL; break; } if (p[0] >= 0) { pEqualizer->setPreset((int)p[0]); } else { if ((int)p[1] != kNumBands) { status = -EINVAL; break; } for (int i = 0; i < kNumBands; i++) { pEqualizer->setGain(i, (int32_t)p[2 + i]); } } pEqualizer->commit(true); } break; default: ALOGV("setParameter() invalid param %d", param); status = -EINVAL; break; } return status; } // end Equalizer_setParameter } // namespace } // namespace // //--- Effect Control Interface Implementation // extern "C" int Equalizer_process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) { android::EqualizerContext * pContext = (android::EqualizerContext *) self; if (pContext == NULL) { return -EINVAL; } if (inBuffer == NULL || inBuffer->raw == NULL || outBuffer == NULL || outBuffer->raw == NULL || inBuffer->frameCount != outBuffer->frameCount) { return -EINVAL; } if (pContext->state == EQUALIZER_STATE_UNINITIALIZED) { return -EINVAL; } if (pContext->state == EQUALIZER_STATE_INITIALIZED) { return -ENODATA; } pContext->adapter.process(inBuffer->raw, outBuffer->raw, outBuffer->frameCount); return 0; } // end Equalizer_process extern "C" int Equalizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t *replySize, void *pReplyData) { android::EqualizerContext * pContext = (android::EqualizerContext *) self; int retsize; if (pContext == NULL || pContext->state == EQUALIZER_STATE_UNINITIALIZED) { return -EINVAL; } android::AudioEqualizer * pEqualizer = pContext->pEqualizer; ALOGV("Equalizer_command command %d cmdSize %d",cmdCode, cmdSize); switch (cmdCode) { case EFFECT_CMD_INIT: if (pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } *(int *) pReplyData = Equalizer_init(pContext); break; case EFFECT_CMD_SET_CONFIG: if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } *(int *) pReplyData = Equalizer_setConfig(pContext, (effect_config_t *) pCmdData); break; case EFFECT_CMD_GET_CONFIG: if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) { return -EINVAL; } Equalizer_getConfig(pContext, (effect_config_t *) pCmdData); break; case EFFECT_CMD_RESET: Equalizer_setConfig(pContext, &pContext->config); break; case EFFECT_CMD_GET_PARAM: { if (pCmdData == NULL || cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || *replySize < (sizeof(effect_param_t) + sizeof(int32_t))) { return -EINVAL; } effect_param_t *p = (effect_param_t *)pCmdData; memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize); p = (effect_param_t *)pReplyData; int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); p->status = android::Equalizer_getParameter(pEqualizer, (int32_t *)p->data, &p->vsize, p->data + voffset); *replySize = sizeof(effect_param_t) + voffset + p->vsize; ALOGV("Equalizer_command EFFECT_CMD_GET_PARAM *pCmdData %d, *replySize %d, *pReplyData %08x %08x", *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)), *replySize, *(int32_t *)((char *)pReplyData + sizeof(effect_param_t) + voffset), *(int32_t *)((char *)pReplyData + sizeof(effect_param_t) + voffset + sizeof(int32_t))); } break; case EFFECT_CMD_SET_PARAM: { ALOGV("Equalizer_command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData); if (pCmdData == NULL || cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) || pReplyData == NULL || *replySize != sizeof(int32_t)) { return -EINVAL; } effect_param_t *p = (effect_param_t *) pCmdData; *(int *)pReplyData = android::Equalizer_setParameter(pEqualizer, (int32_t *)p->data, p->data + p->psize); } break; case EFFECT_CMD_ENABLE: if (pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } if (pContext->state != EQUALIZER_STATE_INITIALIZED) { return -ENOSYS; } pContext->state = EQUALIZER_STATE_ACTIVE; ALOGV("EFFECT_CMD_ENABLE() OK"); *(int *)pReplyData = 0; break; case EFFECT_CMD_DISABLE: if (pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } if (pContext->state != EQUALIZER_STATE_ACTIVE) { return -ENOSYS; } pContext->state = EQUALIZER_STATE_INITIALIZED; ALOGV("EFFECT_CMD_DISABLE() OK"); *(int *)pReplyData = 0; break; case EFFECT_CMD_SET_DEVICE: case EFFECT_CMD_SET_VOLUME: case EFFECT_CMD_SET_AUDIO_MODE: break; default: ALOGW("Equalizer_command invalid command %d",cmdCode); return -EINVAL; } return 0; } extern "C" int Equalizer_getDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor) { android::EqualizerContext * pContext = (android::EqualizerContext *) self; if (pContext == NULL || pDescriptor == NULL) { ALOGV("Equalizer_getDescriptor() invalid param"); return -EINVAL; } *pDescriptor = android::gEqualizerDescriptor; return 0; } // effect_handle_t interface implementation for equalizer effect const struct effect_interface_s gEqualizerInterface = { Equalizer_process, Equalizer_command, Equalizer_getDescriptor, NULL }; audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, name : "Test Equalizer Library", implementor : "The Android Open Source Project", create_effect : android::EffectCreate, release_effect : android::EffectRelease, get_descriptor : android::EffectGetDescriptor, };