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
This commit is contained in:
30
media/libeffects/visualizer/Android.mk
Normal file
30
media/libeffects/visualizer/Android.mk
Normal file
@ -0,0 +1,30 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# Visualizer library
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
EffectVisualizer.cpp
|
||||
|
||||
LOCAL_CFLAGS+= -O2
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
|
||||
LOCAL_MODULE:= libvisualizer
|
||||
|
||||
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
|
||||
LOCAL_LDLIBS += -ldlS
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(call include-path-for, graphics corecg)
|
||||
|
||||
LOCAL_PRELINK_MODULE := false
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
401
media/libeffects/visualizer/EffectVisualizer.cpp
Normal file
401
media/libeffects/visualizer/EffectVisualizer.cpp
Normal file
@ -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 <cutils/log.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <new>
|
||||
#include <media/EffectVisualizerApi.h>
|
||||
|
||||
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
|
||||
|
Reference in New Issue
Block a user