EffectVisualizer.cpp revision 6d8b694d999e9be7d5dcc336535832a80fb6f61f
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#define LOG_TAG "Visualizer" 18//#define LOG_NDEBUG 0 19#include <cutils/log.h> 20#include <assert.h> 21#include <stdlib.h> 22#include <string.h> 23#include <new> 24#include <audio_effects/effect_visualizer.h> 25 26 27extern "C" { 28 29// effect_handle_t interface implementation for visualizer effect 30extern const struct effect_interface_s gVisualizerInterface; 31 32// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b 33const effect_descriptor_t gVisualizerDescriptor = { 34 {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type 35 {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid 36 EFFECT_CONTROL_API_VERSION, 37 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST), 38 0, // TODO 39 1, 40 "Visualizer", 41 "The Android Open Source Project", 42}; 43 44enum visualizer_state_e { 45 VISUALIZER_STATE_UNINITIALIZED, 46 VISUALIZER_STATE_INITIALIZED, 47 VISUALIZER_STATE_ACTIVE, 48}; 49 50struct VisualizerContext { 51 const struct effect_interface_s *mItfe; 52 effect_config_t mConfig; 53 uint32_t mState; 54 uint32_t mCaptureIdx; 55 uint32_t mCaptureSize; 56 uint32_t mCurrentBuf; 57 uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX]; 58}; 59 60 61// 62//--- Local functions 63// 64 65void Visualizer_reset(VisualizerContext *pContext) 66{ 67 pContext->mCaptureIdx = 0; 68 pContext->mCurrentBuf = 0; 69 memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX); 70 memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX); 71} 72 73//---------------------------------------------------------------------------- 74// Visualizer_configure() 75//---------------------------------------------------------------------------- 76// Purpose: Set input and output audio configuration. 77// 78// Inputs: 79// pContext: effect engine context 80// pConfig: pointer to effect_config_t structure holding input and output 81// configuration parameters 82// 83// Outputs: 84// 85//---------------------------------------------------------------------------- 86 87int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig) 88{ 89 LOGV("Visualizer_configure start"); 90 91 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL; 92 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL; 93 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL; 94 if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL; 95 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE && 96 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL; 97 if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; 98 99 memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t)); 100 101 Visualizer_reset(pContext); 102 103 return 0; 104} 105 106 107//---------------------------------------------------------------------------- 108// Visualizer_init() 109//---------------------------------------------------------------------------- 110// Purpose: Initialize engine with default configuration. 111// 112// Inputs: 113// pContext: effect engine context 114// 115// Outputs: 116// 117//---------------------------------------------------------------------------- 118 119int Visualizer_init(VisualizerContext *pContext) 120{ 121 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; 122 pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 123 pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 124 pContext->mConfig.inputCfg.samplingRate = 44100; 125 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL; 126 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL; 127 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL; 128 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; 129 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; 130 pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 131 pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 132 pContext->mConfig.outputCfg.samplingRate = 44100; 133 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL; 134 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; 135 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL; 136 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; 137 138 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX; 139 140 Visualizer_configure(pContext, &pContext->mConfig); 141 142 return 0; 143} 144 145// 146//--- Effect Library Interface Implementation 147// 148 149int VisualizerLib_QueryNumberEffects(uint32_t *pNumEffects) { 150 *pNumEffects = 1; 151 return 0; 152} 153 154int VisualizerLib_QueryEffect(uint32_t index, 155 effect_descriptor_t *pDescriptor) { 156 if (pDescriptor == NULL) { 157 return -EINVAL; 158 } 159 if (index > 0) { 160 return -EINVAL; 161 } 162 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t)); 163 return 0; 164} 165 166int VisualizerLib_Create(effect_uuid_t *uuid, 167 int32_t sessionId, 168 int32_t ioId, 169 effect_handle_t *pHandle) { 170 int ret; 171 int i; 172 173 if (pHandle == NULL || uuid == NULL) { 174 return -EINVAL; 175 } 176 177 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) { 178 return -EINVAL; 179 } 180 181 VisualizerContext *pContext = new VisualizerContext; 182 183 pContext->mItfe = &gVisualizerInterface; 184 pContext->mState = VISUALIZER_STATE_UNINITIALIZED; 185 186 ret = Visualizer_init(pContext); 187 if (ret < 0) { 188 LOGW("VisualizerLib_Create() init failed"); 189 delete pContext; 190 return ret; 191 } 192 193 *pHandle = (effect_handle_t)pContext; 194 195 pContext->mState = VISUALIZER_STATE_INITIALIZED; 196 197 LOGV("VisualizerLib_Create %p", pContext); 198 199 return 0; 200 201} 202 203int VisualizerLib_Release(effect_handle_t handle) { 204 VisualizerContext * pContext = (VisualizerContext *)handle; 205 206 LOGV("VisualizerLib_Release %p", handle); 207 if (pContext == NULL) { 208 return -EINVAL; 209 } 210 pContext->mState = VISUALIZER_STATE_UNINITIALIZED; 211 delete pContext; 212 213 return 0; 214} 215 216int VisualizerLib_GetDescriptor(effect_uuid_t *uuid, 217 effect_descriptor_t *pDescriptor) { 218 219 if (pDescriptor == NULL || uuid == NULL){ 220 LOGV("VisualizerLib_GetDescriptor() called with NULL pointer"); 221 return -EINVAL; 222 } 223 224 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) { 225 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t)); 226 return 0; 227 } 228 229 return -EINVAL; 230} /* end VisualizerLib_GetDescriptor */ 231 232// 233//--- Effect Control Interface Implementation 234// 235 236static inline int16_t clamp16(int32_t sample) 237{ 238 if ((sample>>15) ^ (sample>>31)) 239 sample = 0x7FFF ^ (sample>>31); 240 return sample; 241} 242 243int Visualizer_process( 244 effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) 245{ 246 VisualizerContext * pContext = (VisualizerContext *)self; 247 248 if (pContext == NULL) { 249 return -EINVAL; 250 } 251 252 if (inBuffer == NULL || inBuffer->raw == NULL || 253 outBuffer == NULL || outBuffer->raw == NULL || 254 inBuffer->frameCount != outBuffer->frameCount || 255 inBuffer->frameCount == 0) { 256 return -EINVAL; 257 } 258 259 // all code below assumes stereo 16 bit PCM output and input 260 261 // derive capture scaling factor from peak value in current buffer 262 // this gives more interesting captures for display. 263 int32_t shift = 32; 264 int len = inBuffer->frameCount * 2; 265 for (int i = 0; i < len; i++) { 266 int32_t smp = inBuffer->s16[i]; 267 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range 268 int32_t clz = __builtin_clz(smp); 269 if (shift > clz) shift = clz; 270 } 271 // A maximum amplitude signal will have 17 leading zeros, which we want to 272 // translate to a shift of 8 (for converting 16 bit to 8 bit) 273 shift = 25 - shift; 274 // Never scale by less than 8 to avoid returning unaltered PCM signal. 275 if (shift < 3) { 276 shift = 3; 277 } 278 // add one to combine the division by 2 needed after summing left and right channels below 279 shift++; 280 281 uint32_t captIdx; 282 uint32_t inIdx; 283 uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf]; 284 for (inIdx = 0, captIdx = pContext->mCaptureIdx; 285 inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize; 286 inIdx++, captIdx++) { 287 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]; 288 smp = smp >> shift; 289 buf[captIdx] = ((uint8_t)smp)^0x80; 290 } 291 pContext->mCaptureIdx = captIdx; 292 293 // go to next buffer when buffer full 294 if (pContext->mCaptureIdx == pContext->mCaptureSize) { 295 pContext->mCurrentBuf ^= 1; 296 pContext->mCaptureIdx = 0; 297 } 298 299 if (inBuffer->raw != outBuffer->raw) { 300 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) { 301 for (size_t i = 0; i < outBuffer->frameCount*2; i++) { 302 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]); 303 } 304 } else { 305 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t)); 306 } 307 } 308 if (pContext->mState != VISUALIZER_STATE_ACTIVE) { 309 return -ENODATA; 310 } 311 return 0; 312} // end Visualizer_process 313 314int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, 315 void *pCmdData, uint32_t *replySize, void *pReplyData) { 316 317 VisualizerContext * pContext = (VisualizerContext *)self; 318 int retsize; 319 320 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) { 321 return -EINVAL; 322 } 323 324// LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize); 325 326 switch (cmdCode) { 327 case EFFECT_CMD_INIT: 328 if (pReplyData == NULL || *replySize != sizeof(int)) { 329 return -EINVAL; 330 } 331 *(int *) pReplyData = Visualizer_init(pContext); 332 break; 333 case EFFECT_CMD_CONFIGURE: 334 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) 335 || pReplyData == NULL || *replySize != sizeof(int)) { 336 return -EINVAL; 337 } 338 *(int *) pReplyData = Visualizer_configure(pContext, 339 (effect_config_t *) pCmdData); 340 break; 341 case EFFECT_CMD_RESET: 342 Visualizer_reset(pContext); 343 break; 344 case EFFECT_CMD_ENABLE: 345 if (pReplyData == NULL || *replySize != sizeof(int)) { 346 return -EINVAL; 347 } 348 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) { 349 return -ENOSYS; 350 } 351 pContext->mState = VISUALIZER_STATE_ACTIVE; 352 LOGV("EFFECT_CMD_ENABLE() OK"); 353 *(int *)pReplyData = 0; 354 break; 355 case EFFECT_CMD_DISABLE: 356 if (pReplyData == NULL || *replySize != sizeof(int)) { 357 return -EINVAL; 358 } 359 if (pContext->mState != VISUALIZER_STATE_ACTIVE) { 360 return -ENOSYS; 361 } 362 pContext->mState = VISUALIZER_STATE_INITIALIZED; 363 LOGV("EFFECT_CMD_DISABLE() OK"); 364 *(int *)pReplyData = 0; 365 break; 366 case EFFECT_CMD_GET_PARAM: { 367 if (pCmdData == NULL || 368 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || 369 pReplyData == NULL || 370 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) { 371 return -EINVAL; 372 } 373 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t)); 374 effect_param_t *p = (effect_param_t *)pReplyData; 375 p->status = 0; 376 *replySize = sizeof(effect_param_t) + sizeof(uint32_t); 377 if (p->psize != sizeof(uint32_t) || 378 *(uint32_t *)p->data != VISUALIZER_PARAM_CAPTURE_SIZE) { 379 p->status = -EINVAL; 380 break; 381 } 382 LOGV("get mCaptureSize = %d", pContext->mCaptureSize); 383 *((uint32_t *)p->data + 1) = pContext->mCaptureSize; 384 p->vsize = sizeof(uint32_t); 385 *replySize += sizeof(uint32_t); 386 } break; 387 case EFFECT_CMD_SET_PARAM: { 388 if (pCmdData == NULL || 389 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) || 390 pReplyData == NULL || *replySize != sizeof(int32_t)) { 391 return -EINVAL; 392 } 393 *(int32_t *)pReplyData = 0; 394 effect_param_t *p = (effect_param_t *)pCmdData; 395 if (p->psize != sizeof(uint32_t) || 396 p->vsize != sizeof(uint32_t) || 397 *(uint32_t *)p->data != VISUALIZER_PARAM_CAPTURE_SIZE) { 398 *(int32_t *)pReplyData = -EINVAL; 399 break;; 400 } 401 pContext->mCaptureSize = *((uint32_t *)p->data + 1); 402 LOGV("set mCaptureSize = %d", pContext->mCaptureSize); 403 } break; 404 case EFFECT_CMD_SET_DEVICE: 405 case EFFECT_CMD_SET_VOLUME: 406 case EFFECT_CMD_SET_AUDIO_MODE: 407 break; 408 409 410 case VISUALIZER_CMD_CAPTURE: 411 if (pReplyData == NULL || *replySize != pContext->mCaptureSize) { 412 LOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d", 413 *replySize, pContext->mCaptureSize); 414 return -EINVAL; 415 } 416 if (pContext->mState == VISUALIZER_STATE_ACTIVE) { 417 memcpy(pReplyData, 418 pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1], 419 pContext->mCaptureSize); 420 } else { 421 memset(pReplyData, 0x80, pContext->mCaptureSize); 422 } 423 break; 424 425 default: 426 LOGW("Visualizer_command invalid command %d",cmdCode); 427 return -EINVAL; 428 } 429 430 return 0; 431} 432 433/* Effect Control Interface Implementation: get_descriptor */ 434int Visualizer_getDescriptor(effect_handle_t self, 435 effect_descriptor_t *pDescriptor) 436{ 437 VisualizerContext * pContext = (VisualizerContext *) self; 438 439 if (pContext == NULL || pDescriptor == NULL) { 440 LOGV("Visualizer_getDescriptor() invalid param"); 441 return -EINVAL; 442 } 443 444 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t)); 445 446 return 0; 447} /* end Visualizer_getDescriptor */ 448 449// effect_handle_t interface implementation for visualizer effect 450const struct effect_interface_s gVisualizerInterface = { 451 Visualizer_process, 452 Visualizer_command, 453 Visualizer_getDescriptor 454}; 455 456 457audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 458 tag : AUDIO_EFFECT_LIBRARY_TAG, 459 version : EFFECT_LIBRARY_API_VERSION, 460 name : "Visualizer Library", 461 implementor : "The Android Open Source Project", 462 query_num_effects : VisualizerLib_QueryNumberEffects, 463 query_effect : VisualizerLib_QueryEffect, 464 create_effect : VisualizerLib_Create, 465 release_effect : VisualizerLib_Release, 466 get_descriptor : VisualizerLib_GetDescriptor, 467}; 468 469}; // extern "C" 470