From 2c8e5cab3faa6d360e222b7a6c40a80083d021ac Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 9 Jul 2010 12:28:50 -0700 Subject: First submission of audio effect library from NXP software. This CL contains the first open sourceable version of the audio effect library from NXP software. The effects implemented are: - Bass boost - Virtualizer (stereo widening) - Equalizer - Spectrum analyzer Source file for the effect engines are located under libeffects/lvm/lib The wrapper implementing the interface with the audio effect framework in under libeffects/lvm/wrapper The code of other effect libraries has also been reorganized fo clarity: - the effect factory is now under libeffects/factory - the test equalizer and reverb effects are under libeffect/testlibs - the visualizer is under libeffects/virtualizer Change-Id: I8d91e2181f81b89f8fc0c1e1e6bf552c5809b2eb --- media/libeffects/visualizer/EffectVisualizer.cpp | 401 +++++++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 media/libeffects/visualizer/EffectVisualizer.cpp (limited to 'media/libeffects/visualizer/EffectVisualizer.cpp') diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp new file mode 100644 index 0000000..bcda06e --- /dev/null +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -0,0 +1,401 @@ +/* + * 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. + */ + +#define LOG_TAG "Visualizer" +//#define LOG_NDEBUG 0 +#include +#include +#include +#include +#include +#include + +namespace android { + +// effect_interface_t interface implementation for visualizer effect +extern "C" const struct effect_interface_s gVisualizerInterface; + +// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b +const effect_descriptor_t gVisualizerDescriptor = { + {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type + {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST), + 0, // TODO + 1, + "Visualizer", + "Google Inc.", +}; + +enum visualizer_state_e { + VISUALIZER_STATE_UNINITIALIZED, + VISUALIZER_STATE_INITIALIZED, + VISUALIZER_STATE_ACTIVE, +}; + +struct VisualizerContext { + const struct effect_interface_s *mItfe; + effect_config_t mConfig; + uint32_t mState; + uint32_t mCaptureIdx; + uint32_t mCaptureSize; + uint32_t mCurrentBuf; + uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX]; +}; + + +// +//--- Local functions +// + +void Visualizer_reset(VisualizerContext *pContext) +{ + pContext->mCaptureIdx = 0; + pContext->mCurrentBuf = 0; + memset(pContext->mCaptureBuf[0], 0, VISUALIZER_CAPTURE_SIZE_MAX); + memset(pContext->mCaptureBuf[1], 0, VISUALIZER_CAPTURE_SIZE_MAX); +} + +//---------------------------------------------------------------------------- +// Visualizer_configure() +//---------------------------------------------------------------------------- +// 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 Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig) +{ + LOGV("Visualizer_configure start"); + + if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL; + if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL; + if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL; + if (pConfig->inputCfg.channels != CHANNEL_STEREO) return -EINVAL; + if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE && + pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL; + if (pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15) return -EINVAL; + + memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t)); + + Visualizer_reset(pContext); + + return 0; +} + + +//---------------------------------------------------------------------------- +// Visualizer_init() +//---------------------------------------------------------------------------- +// Purpose: Initialize engine with default configuration. +// +// Inputs: +// pContext: effect engine context +// +// Outputs: +// +//---------------------------------------------------------------------------- + +int Visualizer_init(VisualizerContext *pContext) +{ + pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + pContext->mConfig.inputCfg.channels = CHANNEL_STEREO; + pContext->mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15; + pContext->mConfig.inputCfg.samplingRate = 44100; + pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL; + pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL; + pContext->mConfig.inputCfg.bufferProvider.cookie = NULL; + pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; + pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + pContext->mConfig.outputCfg.channels = CHANNEL_STEREO; + pContext->mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15; + pContext->mConfig.outputCfg.samplingRate = 44100; + pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL; + pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; + pContext->mConfig.outputCfg.bufferProvider.cookie = NULL; + pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; + + pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX; + + Visualizer_configure(pContext, &pContext->mConfig); + + return 0; +} + +// +//--- Effect Library Interface Implementation +// + +extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) { + *pNumEffects = 1; + return 0; +} + +extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) { + if (pDescriptor == NULL) { + return -EINVAL; + } + if (index > 0) { + return -EINVAL; + } + memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t)); + return 0; +} + +extern "C" int EffectCreate(effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_interface_t *pInterface) { + int ret; + int i; + + if (pInterface == NULL || uuid == NULL) { + return -EINVAL; + } + + if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) { + return -EINVAL; + } + + VisualizerContext *pContext = new VisualizerContext; + + pContext->mItfe = &gVisualizerInterface; + pContext->mState = VISUALIZER_STATE_UNINITIALIZED; + + ret = Visualizer_init(pContext); + if (ret < 0) { + LOGW("EffectCreate() init failed"); + delete pContext; + return ret; + } + + *pInterface = (effect_interface_t)pContext; + + pContext->mState = VISUALIZER_STATE_INITIALIZED; + + LOGV("EffectCreate %p", pContext); + + return 0; + +} + +extern "C" int EffectRelease(effect_interface_t interface) { + VisualizerContext * pContext = (VisualizerContext *)interface; + + LOGV("EffectRelease %p", interface); + if (pContext == NULL) { + return -EINVAL; + } + pContext->mState = VISUALIZER_STATE_UNINITIALIZED; + delete pContext; + + return 0; +} + +// +//--- Effect Control Interface Implementation +// + +static inline int16_t clamp16(int32_t sample) +{ + if ((sample>>15) ^ (sample>>31)) + sample = 0x7FFF ^ (sample>>31); + return sample; +} + +extern "C" int Visualizer_process( + effect_interface_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) +{ + android::VisualizerContext * pContext = (android::VisualizerContext *)self; + + if (pContext == NULL) { + return -EINVAL; + } + if (pContext->mState != VISUALIZER_STATE_ACTIVE) { + return -ENODATA; + } + + if (inBuffer == NULL || inBuffer->raw == NULL || + outBuffer == NULL || outBuffer->raw == NULL || + inBuffer->frameCount != outBuffer->frameCount || + inBuffer->frameCount == 0) { + return -EINVAL; + } + + // all code below assumes stereo 16 bit PCM output and input + uint32_t captIdx; + uint32_t inIdx; + uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf]; + for (inIdx = 0, captIdx = pContext->mCaptureIdx; + inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize; + inIdx++, captIdx++) { + int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]; + smp = (smp + (1 << 8)) >> 9; + buf[captIdx] = ((uint8_t)smp)^0x80; + } + pContext->mCaptureIdx = captIdx; + + // go to next buffer when buffer full + if (pContext->mCaptureIdx == pContext->mCaptureSize) { + pContext->mCurrentBuf ^= 1; + pContext->mCaptureIdx = 0; + } + + if (inBuffer->raw != outBuffer->raw) { + if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) { + for (size_t i = 0; i < outBuffer->frameCount*2; i++) { + outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]); + } + } else { + memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t)); + } + } + return 0; +} // end Visualizer_process + +extern "C" int Visualizer_command(effect_interface_t self, int cmdCode, int cmdSize, + void *pCmdData, int *replySize, void *pReplyData) { + + android::VisualizerContext * pContext = (android::VisualizerContext *)self; + int retsize; + + if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) { + return -EINVAL; + } + +// LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize); + + switch (cmdCode) { + case EFFECT_CMD_INIT: + if (pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + *(int *) pReplyData = Visualizer_init(pContext); + break; + case EFFECT_CMD_CONFIGURE: + if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) + || pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + *(int *) pReplyData = Visualizer_configure(pContext, + (effect_config_t *) pCmdData); + break; + case EFFECT_CMD_RESET: + Visualizer_reset(pContext); + break; + case EFFECT_CMD_ENABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + if (pContext->mState != VISUALIZER_STATE_INITIALIZED) { + return -ENOSYS; + } + pContext->mState = VISUALIZER_STATE_ACTIVE; + LOGV("EFFECT_CMD_ENABLE() OK"); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_DISABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + if (pContext->mState != VISUALIZER_STATE_ACTIVE) { + return -ENOSYS; + } + pContext->mState = VISUALIZER_STATE_INITIALIZED; + LOGV("EFFECT_CMD_DISABLE() OK"); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_GET_PARAM: { + if (pCmdData == NULL || + cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || + pReplyData == NULL || + *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) { + return -EINVAL; + } + memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t)); + effect_param_t *p = (effect_param_t *)pReplyData; + p->status = 0; + *replySize = sizeof(effect_param_t) + sizeof(uint32_t); + if (p->psize != sizeof(uint32_t) || + *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) { + p->status = -EINVAL; + break; + } + LOGV("get mCaptureSize = %d", pContext->mCaptureSize); + *((uint32_t *)p->data + 1) = pContext->mCaptureSize; + p->vsize = sizeof(uint32_t); + *replySize += sizeof(uint32_t); + } break; + case EFFECT_CMD_SET_PARAM: { + if (pCmdData == NULL || + cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) || + pReplyData == NULL || *replySize != sizeof(int32_t)) { + return -EINVAL; + } + *(int32_t *)pReplyData = 0; + effect_param_t *p = (effect_param_t *)pCmdData; + if (p->psize != sizeof(uint32_t) || + p->vsize != sizeof(uint32_t) || + *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) { + *(int32_t *)pReplyData = -EINVAL; + break;; + } + pContext->mCaptureSize = *((uint32_t *)p->data + 1); + LOGV("set mCaptureSize = %d", pContext->mCaptureSize); + } break; + case EFFECT_CMD_SET_DEVICE: + case EFFECT_CMD_SET_VOLUME: + case EFFECT_CMD_SET_AUDIO_MODE: + break; + + + case VISU_CMD_CAPTURE: + if (pReplyData == NULL || *replySize != (int)pContext->mCaptureSize) { + LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d", + *replySize, pContext->mCaptureSize); + return -EINVAL; + } + if (pContext->mState == VISUALIZER_STATE_ACTIVE) { + memcpy(pReplyData, + pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1], + pContext->mCaptureSize); + } else { + memset(pReplyData, 0x80, pContext->mCaptureSize); + } + break; + + default: + LOGW("Visualizer_command invalid command %d",cmdCode); + return -EINVAL; + } + + return 0; +} + +// effect_interface_t interface implementation for visualizer effect +const struct effect_interface_s gVisualizerInterface = { + Visualizer_process, + Visualizer_command +}; + +} // namespace + -- cgit v1.1