am cf3fa85c
: Merge "Fix issue 2667796: [Audio Effect Framework] Effect factory and libraries." into kraken
This commit is contained in:
80
include/media/AudioCommon.h
Normal file
80
include/media/AudioCommon.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIOCOMMON_H_
|
||||
#define ANDROID_AUDIOCOMMON_H_
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Common definitions for PCM audio
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
|
||||
// PCM Sample format
|
||||
enum audio_format_e {
|
||||
PCM_FORMAT_S15 = 1, // PCM signed 16 bits, must be 1 for backward compatibility
|
||||
PCM_FORMAT_U8 = 2, // PCM unsigned 8 bits, must be 2 for backward compatibility
|
||||
PCM_FORMAT_S7_24 // signed 7.24 fixed point representation
|
||||
};
|
||||
|
||||
// Channel mask definitions
|
||||
enum audio_channels_e {
|
||||
CHANNEL_FRONT_LEFT = 0x4, // front left channel
|
||||
CHANNEL_FRONT_RIGHT = 0x8, // front right channel
|
||||
CHANNEL_FRONT_CENTER = 0x10, // front center channel
|
||||
CHANNEL_LOW_FREQUENCY = 0x20, // low frequency channel
|
||||
CHANNEL_BACK_LEFT = 0x40, // back left channel
|
||||
CHANNEL_BACK_RIGHT = 0x80, // back right channel
|
||||
CHANNEL_FRONT_LEFT_OF_CENTER = 0x100, // front left of center channel
|
||||
CHANNEL_FRONT_RIGHT_OF_CENTER = 0x200, // front right of center channel
|
||||
CHANNEL_BACK_CENTER = 0x400, // back center channel
|
||||
CHANNEL_MONO = CHANNEL_FRONT_LEFT,
|
||||
CHANNEL_STEREO = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT),
|
||||
CHANNEL_QUAD = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT),
|
||||
CHANNEL_SURROUND = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER),
|
||||
CHANNEL_5POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT),
|
||||
CHANNEL_7POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT |
|
||||
CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER),
|
||||
};
|
||||
|
||||
// Render device definitions
|
||||
enum audio_device_e {
|
||||
DEVICE_EARPIECE = 0x1, // earpiece
|
||||
DEVICE_SPEAKER = 0x2, // speaker
|
||||
DEVICE_WIRED_HEADSET = 0x4, // wired headset, with microphone
|
||||
DEVICE_WIRED_HEADPHONE = 0x8, // wired headphone, without microphone
|
||||
DEVICE_BLUETOOTH_SCO = 0x10, // generic bluetooth SCO
|
||||
DEVICE_BLUETOOTH_SCO_HEADSET = 0x20, // bluetooth SCO headset
|
||||
DEVICE_BLUETOOTH_SCO_CARKIT = 0x40, // bluetooth SCO car kit
|
||||
DEVICE_BLUETOOTH_A2DP = 0x80, // generic bluetooth A2DP
|
||||
DEVICE_BLUETOOTH_A2DP_HEADPHONES = 0x100, // bluetooth A2DP headphones
|
||||
DEVICE_BLUETOOTH_A2DP_SPEAKER = 0x200, // bluetooth A2DP speakers
|
||||
DEVICE_AUX_DIGITAL = 0x400 // digital output
|
||||
};
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_AUDIOCOMMON_H_*/
|
@ -20,6 +20,7 @@
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/threads.h>
|
||||
#include <media/IAudioFlinger.h>
|
||||
#include <media/AudioCommon.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
@ -50,8 +51,8 @@ public:
|
||||
|
||||
// Audio sub formats (see AudioSystem::audio_format).
|
||||
enum pcm_sub_format {
|
||||
PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
|
||||
PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility
|
||||
PCM_SUB_16_BIT = PCM_FORMAT_S15, // must be 1 for backward compatibility
|
||||
PCM_SUB_8_BIT = PCM_FORMAT_U8, // must be 2 for backward compatibility
|
||||
};
|
||||
|
||||
// MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
|
||||
@ -103,26 +104,21 @@ public:
|
||||
// Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java
|
||||
enum audio_channels {
|
||||
// output channels
|
||||
CHANNEL_OUT_FRONT_LEFT = 0x4,
|
||||
CHANNEL_OUT_FRONT_RIGHT = 0x8,
|
||||
CHANNEL_OUT_FRONT_CENTER = 0x10,
|
||||
CHANNEL_OUT_LOW_FREQUENCY = 0x20,
|
||||
CHANNEL_OUT_BACK_LEFT = 0x40,
|
||||
CHANNEL_OUT_BACK_RIGHT = 0x80,
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
|
||||
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
|
||||
CHANNEL_OUT_BACK_CENTER = 0x400,
|
||||
CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
|
||||
CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
|
||||
CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
|
||||
CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
|
||||
CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
|
||||
CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
|
||||
CHANNEL_OUT_FRONT_LEFT = CHANNEL_FRONT_LEFT,
|
||||
CHANNEL_OUT_FRONT_RIGHT = CHANNEL_FRONT_RIGHT,
|
||||
CHANNEL_OUT_FRONT_CENTER = CHANNEL_FRONT_CENTER,
|
||||
CHANNEL_OUT_LOW_FREQUENCY = CHANNEL_LOW_FREQUENCY,
|
||||
CHANNEL_OUT_BACK_LEFT = CHANNEL_BACK_LEFT,
|
||||
CHANNEL_OUT_BACK_RIGHT = CHANNEL_BACK_RIGHT,
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = CHANNEL_FRONT_LEFT_OF_CENTER,
|
||||
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = CHANNEL_FRONT_RIGHT_OF_CENTER,
|
||||
CHANNEL_OUT_BACK_CENTER = CHANNEL_BACK_CENTER,
|
||||
CHANNEL_OUT_MONO = CHANNEL_MONO,
|
||||
CHANNEL_OUT_STEREO = CHANNEL_STEREO,
|
||||
CHANNEL_OUT_QUAD = CHANNEL_QUAD,
|
||||
CHANNEL_OUT_SURROUND = CHANNEL_SURROUND,
|
||||
CHANNEL_OUT_5POINT1 = CHANNEL_5POINT1,
|
||||
CHANNEL_OUT_7POINT1 = CHANNEL_7POINT1,
|
||||
CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER),
|
||||
@ -240,17 +236,17 @@ public:
|
||||
|
||||
enum audio_devices {
|
||||
// output devices
|
||||
DEVICE_OUT_EARPIECE = 0x1,
|
||||
DEVICE_OUT_SPEAKER = 0x2,
|
||||
DEVICE_OUT_WIRED_HEADSET = 0x4,
|
||||
DEVICE_OUT_WIRED_HEADPHONE = 0x8,
|
||||
DEVICE_OUT_BLUETOOTH_SCO = 0x10,
|
||||
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
|
||||
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
|
||||
DEVICE_OUT_AUX_DIGITAL = 0x400,
|
||||
DEVICE_OUT_EARPIECE = DEVICE_EARPIECE,
|
||||
DEVICE_OUT_SPEAKER = DEVICE_SPEAKER,
|
||||
DEVICE_OUT_WIRED_HEADSET = DEVICE_WIRED_HEADSET,
|
||||
DEVICE_OUT_WIRED_HEADPHONE = DEVICE_WIRED_HEADPHONE,
|
||||
DEVICE_OUT_BLUETOOTH_SCO = DEVICE_BLUETOOTH_SCO,
|
||||
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = DEVICE_BLUETOOTH_SCO_HEADSET,
|
||||
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = DEVICE_BLUETOOTH_SCO_CARKIT,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP = DEVICE_BLUETOOTH_A2DP,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = DEVICE_BLUETOOTH_A2DP_HEADPHONES,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = DEVICE_BLUETOOTH_A2DP_SPEAKER,
|
||||
DEVICE_OUT_AUX_DIGITAL = DEVICE_AUX_DIGITAL,
|
||||
DEVICE_OUT_DEFAULT = 0x8000,
|
||||
DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
|
||||
DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
|
||||
|
555
include/media/EffectApi.h
Normal file
555
include/media/EffectApi.h
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTAPI_H_
|
||||
#define ANDROID_EFFECTAPI_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <media/AudioCommon.h>
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect control interface
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// The effect control interface is exposed by each effect engine implementation. It consists of
|
||||
// a set of functions controlling the configuration, activation and process of the engine.
|
||||
// The functions are grouped in a structure of type effect_interface_s:
|
||||
// struct effect_interface_s {
|
||||
// effect_process_t process;
|
||||
// effect_command_t command;
|
||||
// };
|
||||
|
||||
|
||||
// effect_interface_t: Effect control interface handle.
|
||||
// The effect_interface_t serves two purposes regarding the implementation of the effect engine:
|
||||
// - 1 it is the address of a pointer to an effect_interface_s structure where the functions
|
||||
// of the effect control API for a particular effect are located.
|
||||
// - 2 it is the address of the context of a particular effect instance.
|
||||
// A typical implementation in the effect library would define a structure as follows:
|
||||
// struct effect_module_s {
|
||||
// const struct effect_interface_s *itfe;
|
||||
// effect_config_t config;
|
||||
// effect_context_t context;
|
||||
// }
|
||||
// The implementation of EffectCreate() function would then allocate a structure of this
|
||||
// type and return its address as effect_interface_t
|
||||
typedef struct effect_interface_s **effect_interface_t;
|
||||
|
||||
|
||||
// Effect API version 1.0
|
||||
#define EFFECT_API_VERSION 0x0100 // Format 0xMMmm MM: Major version, mm: minor version
|
||||
|
||||
// Maximum length of character strings in structures defines by this API.
|
||||
#define EFFECT_STRING_LEN_MAX 64
|
||||
|
||||
//
|
||||
//--- Effect descriptor structure effect_descriptor_t
|
||||
//
|
||||
|
||||
// Unique effect ID (can be generated from the following site: http://www.itu.int/ITU-T/asn1/uuid.html)
|
||||
// This format is used for both "type" and "uuid" fields of the effect descriptor structure.
|
||||
// - When used for effect type and the engine is implementing and effect corresponding to a standard OpenSL ES
|
||||
// interface, this ID must be the one defined in OpenSLES_IID.h for that interface.
|
||||
// - When used as uuid, it should be a unique UUID for this particular implementation.
|
||||
typedef struct effect_uuid_s {
|
||||
uint32_t timeLow;
|
||||
uint16_t timeMid;
|
||||
uint16_t timeHiAndVersion;
|
||||
uint16_t clockSeq;
|
||||
uint8_t node[6];
|
||||
} effect_uuid_t;
|
||||
|
||||
// NULL UUID definition (matches SL_IID_NULL_)
|
||||
#define EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, { 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } }
|
||||
static const effect_uuid_t EFFECT_UUID_NULL_ = EFFECT_UUID_INITIALIZER;
|
||||
const effect_uuid_t * const EFFECT_UUID_NULL = &EFFECT_UUID_NULL_;
|
||||
const char * const EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210";
|
||||
|
||||
// the effect descriptor contains necessary information to facilitate the enumeration of the effect
|
||||
// engines present in a library.
|
||||
typedef struct effect_descriptor_s {
|
||||
effect_uuid_t type; // UUID corresponding to the OpenSL ES interface implemented by this effect
|
||||
effect_uuid_t uuid; // UUID for this particular implementation
|
||||
uint16_t apiVersion; // Version of the effect API implemented: must match current EFFECT_API_VERSION
|
||||
uint32_t flags; // effect engine capabilities/requirements flags (see below)
|
||||
char name[EFFECT_STRING_LEN_MAX] ; // human readable effect name
|
||||
char implementor[EFFECT_STRING_LEN_MAX] ; // human readable effect implementor name
|
||||
} effect_descriptor_t;
|
||||
|
||||
// definitions for flags field of effect descriptor.
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | description | bits | values
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | connection mode | 0..1 | 0 insert: after track process
|
||||
// | | | 1 auxiliary: connect to track auxiliary
|
||||
// | | | output and use send level
|
||||
// | | | 2 replace: replaces track process function;
|
||||
// | | | must implement SRC, volume and mono to stereo.
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | insertion preference | 2..4 | 0 none
|
||||
// | | | 1 first of the chain
|
||||
// | | | 2 last of the chain
|
||||
// | | | 3 exclusive (only effect in the insert chain)
|
||||
// | | | 4..7 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Volume management | 5..6 | 0 none
|
||||
// | | | 1 implements volume control
|
||||
// | | | 2..3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Device management | 7..8 | 0 none
|
||||
// | | | 1 requires device updates
|
||||
// | | | 2..3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Sample input mode | 9..10 | 0 direct: process() function or EFFECT_CMD_CONFIGURE
|
||||
// | | | command must specify a buffer descriptor
|
||||
// | | | 1 provider: process() function uses the
|
||||
// | | | bufferProvider indicated by the
|
||||
// | | | EFFECT_CMD_CONFIGURE command to request input buffers.
|
||||
// | | | 2 both: both input modes are supported
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Sample output mode | 11..12 | 0 direct: process() function or EFFECT_CMD_CONFIGURE
|
||||
// | | | command must specify a buffer descriptor
|
||||
// | | | 1 provider: process() function uses the
|
||||
// | | | bufferProvider indicated by the
|
||||
// | | | EFFECT_CMD_CONFIGURE command to request output buffers.
|
||||
// | | | 2 both: both output modes are supported
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
|
||||
// insert mode
|
||||
#define EFFECT_FLAG_TYPE_MASK 0x00000003
|
||||
#define EFFECT_FLAG_TYPE_INSERT 0x00000000
|
||||
#define EFFECT_FLAG_TYPE_AUXILIARY 0x00000001
|
||||
#define EFFECT_FLAG_TYPE_REPLACE 0x00000002
|
||||
|
||||
// insert preference
|
||||
#define EFFECT_FLAG_INSERT_MASK 0x0000001C
|
||||
#define EFFECT_FLAG_INSERT_ANY 0x00000000
|
||||
#define EFFECT_FLAG_INSERT_FIRST 0x00000004
|
||||
#define EFFECT_FLAG_INSERT_LAST 0x00000008
|
||||
#define EFFECT_FLAG_INSERT_EXCLUSIVE 0x0000000C
|
||||
|
||||
|
||||
// volume control
|
||||
#define EFFECT_FLAG_VOLUME_MASK 0x00000060
|
||||
#define EFFECT_FLAG_VOLUME_CTRL 0x00000020
|
||||
#define EFFECT_FLAG_VOLUME_NONE 0x00000000
|
||||
|
||||
// device control
|
||||
#define EFFECT_FLAG_DEVICE_MASK 0x00000180
|
||||
#define EFFECT_FLAG_DEVICE_IND 0x00000080
|
||||
#define EFFECT_FLAG_DEVICE_NONE 0x00000000
|
||||
|
||||
// sample input modes
|
||||
#define EFFECT_FLAG_INPUT_MASK 0x00000600
|
||||
#define EFFECT_FLAG_INPUT_DIRECT 0x00000000
|
||||
#define EFFECT_FLAG_INPUT_PROVIDER 0x00000200
|
||||
#define EFFECT_FLAG_INPUT_BOTH 0x00000400
|
||||
|
||||
// sample output modes
|
||||
#define EFFECT_FLAG_OUTPUT_MASK 0x00001800
|
||||
#define EFFECT_FLAG_OUTPUT_DIRECT 0x00000000
|
||||
#define EFFECT_FLAG_OUTPUT_PROVIDER 0x00000800
|
||||
#define EFFECT_FLAG_OUTPUT_BOTH 0x00001000
|
||||
|
||||
// forward definition of type audio_buffer_t
|
||||
typedef struct audio_buffer_s audio_buffer_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: process
|
||||
//
|
||||
// Description: Effect process function. Takes input samples as specified
|
||||
// (count and location) in input buffer descriptor and output processed
|
||||
// samples as specified in output buffer descriptor. If the buffer descriptor
|
||||
// is not specified the function must use either the buffer or the
|
||||
// buffer provider function installed by the EFFECT_CMD_CONFIGURE command.
|
||||
//
|
||||
// NOTE: the process() function implementation should be "real-time safe" that is
|
||||
// it should not perform blocking calls: malloc/free, sleep, read/write/open/close,
|
||||
// pthread_cond_wait/pthread_mutex_lock...
|
||||
//
|
||||
// Input:
|
||||
// effect_interface_t: handle to the effect interface this function
|
||||
// is called on.
|
||||
// inBuffer: buffer descriptor indicating where to read samples to process.
|
||||
// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command.
|
||||
//
|
||||
// inBuffer: buffer descriptor indicating where to write processed samples.
|
||||
// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation
|
||||
// -EINVAL invalid interface handle or
|
||||
// invalid input/output buffer description
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_process_t)(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: command
|
||||
//
|
||||
// Description: Send a command and receive a response to/from effect engine.
|
||||
//
|
||||
// Input:
|
||||
// effect_interface_t: handle to the effect interface this function
|
||||
// is called on.
|
||||
// cmdCode: command code: the command can be a standardized command defined in
|
||||
// effect_command_e (see below) or a proprietary command.
|
||||
// cmdSize: size of command in bytes
|
||||
// pCmdData: pointer to command data
|
||||
// pReplyData: pointer to reply data
|
||||
//
|
||||
// Input/Output:
|
||||
// replySize: maximum size of reply data as input
|
||||
// actual size of reply data as output
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation
|
||||
// -EINVAL invalid interface handle or
|
||||
// invalid command/reply size or format according to command code
|
||||
// The return code should be restricted to indicate problems related to the this
|
||||
// API specification. Status related to the execution of a particular command should be
|
||||
// indicated as part of the reply field.
|
||||
//
|
||||
// *pReplyData updated with command response
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_command_t)(effect_interface_t self, int32_t cmdCode, int32_t cmdSize, void *pCmdData, int32_t *replySize, void *pReplyData);
|
||||
|
||||
|
||||
// Effect control interface definition
|
||||
struct effect_interface_s {
|
||||
effect_process_t process;
|
||||
effect_command_t command;
|
||||
};
|
||||
|
||||
|
||||
//--- Standardized command codes for command function
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | description | command code | command format | reply format
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Initialize effect engine: | EFFECT_CMD_INIT | size: 0 | size: sizeof(int)
|
||||
// | All configurations return to | | data: N/A | data: status
|
||||
// | default | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Apply new audio parameters | EFFECT_CMD_CONFIGURE | size: sizeof(effect_config_t) | size: sizeof(int)
|
||||
// | configurations for input and | | data: effect_config_t | data: status
|
||||
// | output buffers | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Reset effect engine: keep | EFFECT_CMD_RESET | size: 0 | size: 0
|
||||
// | configuration but reset state | | data: N/A | data: N/A
|
||||
// | and buffer content. | | |
|
||||
// | Called by the framework before | | |
|
||||
// | enabling the effect | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Enable the process | EFFECT_CMD_ENABLE | size: 0 | size: sizeof(int)
|
||||
// | Called by the framework before | | data: N/A | data: status
|
||||
// | the first call to process() | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Disable the process | EFFECT_CMD_DISABLE | size: 0 | size: sizeof(int)
|
||||
// | Called by the framework after | | data: N/A | data: status
|
||||
// | the last call to process() | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Set a parameter and apply it | EFFECT_CMD_SET_PARAM | size: sizeof(effect_param_t) | size: sizeof(int)
|
||||
// | immediately | | + size of param + value | data: status
|
||||
// | | | data: effect_param_t |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Set a parameter but apply it | EFFECT_CMD_SET_PARAM_DEFERRED | size: sizeof(effect_param_t) | size: 0
|
||||
// | only when receiving command | | + size of param + value | data: N/A
|
||||
// | EFFECT_CMD_SET_PARAM_COMMIT | | data: effect_param_t |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Apply all previously received | EFFECT_CMD_SET_PARAM_COMMIT | size: 0 | size: sizeof(int)
|
||||
// | EFFECT_CMD_SET_PARAM_DEFERRED | | data: N/A | data: status
|
||||
// | commands | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Get a parameter value | EFFECT_CMD_GET_PARAM | size: sizeof(effect_param_t) | size: sizeof(effect_param_t)
|
||||
// | | | + size of param | + size of param + value
|
||||
// | | | data: effect_param_t | data: effect_param_t
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Set the rendering device the | EFFECT_CMD_SET_DEVICE | size: sizeof(uint32_t) | size: 0
|
||||
// | audio output path is connected | | data: audio_device_e | data: N/A
|
||||
// | to. See audio_device_e in | | |
|
||||
// | AudioCommon.h for device values| | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | Set and get volume. Used by | EFFECT_CMD_SET_VOLUME | size: n * sizeof(uint32_t) | size: n * sizeof(uint32_t)
|
||||
// | audio framework to delegate | | data: volume for each channel | data: volume for each channel
|
||||
// | volume control to effect engine| | defined in effect_config_t in | defined in effect_config_t in
|
||||
// | The engine must return the | | 8.24 fixed point format | 8.24 fixed point format
|
||||
// | volume that should be applied | | |
|
||||
// | before the effect is processed | | |
|
||||
// | The overall volume (the volume | | |
|
||||
// | actually applied by the effect | | |
|
||||
// | multiplied by the returned | | |
|
||||
// | value) should match the | | |
|
||||
// | requested value | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
// | All proprietary effect commands| EFFECT_CMD_FIRST_PROPRIETARY | |
|
||||
// | must use command codes above | | |
|
||||
// | this value. The size and format| | |
|
||||
// | of command and response fields | | |
|
||||
// | is free in this case. | | |
|
||||
// +--------------------------------+-------------------------------+-------------------------------+--------------------------
|
||||
|
||||
|
||||
enum effect_command_e {
|
||||
EFFECT_CMD_INIT, // initialize effect engine
|
||||
EFFECT_CMD_CONFIGURE, // configure effect engine (see effect_config_t)
|
||||
EFFECT_CMD_RESET, // reset effect engine
|
||||
EFFECT_CMD_ENABLE, // enable effect process
|
||||
EFFECT_CMD_DISABLE, // disable effect process
|
||||
EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t)
|
||||
EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred
|
||||
EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred
|
||||
EFFECT_CMD_GET_PARAM, // get parameter
|
||||
EFFECT_CMD_SET_DEVICE, // set audio device (see audio_device_e in AudioCommon.h)
|
||||
EFFECT_CMD_SET_VOLUME, // set volume
|
||||
EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code
|
||||
};
|
||||
|
||||
// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t structure
|
||||
// Multi-channel audio is always interleaved. The channel order is from LSB to MSB with regard to the
|
||||
// channel mask definition in audio_channels_e (AudioCommon.h) e.g :
|
||||
// Stereo: left, right
|
||||
// 5 point 1: front left, front right, front center, low frequency, back left, back right
|
||||
// The buffer size is expressed in frame count, a frame being composed of samples for all
|
||||
// channels at a given time
|
||||
struct audio_buffer_s {
|
||||
size_t frameCount; // number of frames in buffer
|
||||
union {
|
||||
void* raw; // raw pointer to start of buffer
|
||||
int32_t* s32; // pointer to signed 32 bit data at start of buffer
|
||||
int16_t* s16; // pointer to signed 16 bit data at start of buffer
|
||||
uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer
|
||||
};
|
||||
};
|
||||
|
||||
// the buffer_provider_s structure contains functions that can be used
|
||||
// by the effect engine process() function to query and release input
|
||||
// or output audio buffer.
|
||||
// The getBuffer() function is called to retrieve a buffer where data
|
||||
// should read from or written to by process() function.
|
||||
// The releaseBuffer() function MUST be called when the buffer retrieved
|
||||
// with getBuffer() is not needed anymore.
|
||||
// The process function should use the buffer provider mechanism to retrieve
|
||||
// input or output buffer if the inBuffer or outBuffer passed as argument is NULL
|
||||
// and the buffer configuration (buffer_config_t) given by the EFFECT_CMD_CONFIGURE
|
||||
// command did not specify an audio buffer.
|
||||
|
||||
typedef int32_t (* buffer_function_t)(void *cookie, audio_buffer_t *buffer);
|
||||
|
||||
typedef struct buffer_provider_s {
|
||||
buffer_function_t getBuffer; // retrieve next buffer
|
||||
buffer_function_t releaseBuffer; // release used buffer
|
||||
void *cookie; // for use by client of buffer provider functions
|
||||
} buffer_provider_t;
|
||||
|
||||
// The buffer_config_s structure specifies the input or output audio format
|
||||
// to be used by the effect engine. It is part of the effect_config_t
|
||||
// structure that defines both input and output buffer configurations and is
|
||||
// passed by the EFFECT_CMD_CONFIGURE command.
|
||||
typedef struct buffer_config_s {
|
||||
audio_buffer_t buffer; // buffer for use by process() function is not passed explicitly
|
||||
uint32_t samplingRate; // sampling rate
|
||||
uint32_t channels; // channel mask (see audio_channels_e in AudioCommon.h)
|
||||
buffer_provider_t bufferProvider; // buffer provider
|
||||
uint8_t format; // PCM format (see audio_format_e in AudioCommon.h)
|
||||
uint8_t accessMode; // read/write or accumulate in buffer (effect_buffer_access_e)
|
||||
uint16_t mask; // indicates which of the above fields is valid
|
||||
} buffer_config_t;
|
||||
|
||||
// values for "accessMode" field of buffer_config_t:
|
||||
// overwrite, read only, accumulate (read/modify/write)
|
||||
enum effect_buffer_access_e {
|
||||
EFFECT_BUFFER_ACCESS_WRITE,
|
||||
EFFECT_BUFFER_ACCESS_READ,
|
||||
EFFECT_BUFFER_ACCESS_ACCUMULATE
|
||||
|
||||
};
|
||||
|
||||
// values for bit field "mask" in buffer_config_t. If a bit is set, the corresponding field
|
||||
// in buffer_config_t must be taken into account when executing the EFFECT_CMD_CONFIGURE command
|
||||
#define EFFECT_CONFIG_BUFFER 0x0001 // buffer field must be taken into account
|
||||
#define EFFECT_CONFIG_SMP_RATE 0x0002 // samplingRate field must be taken into account
|
||||
#define EFFECT_CONFIG_CHANNELS 0x0004 // channels field must be taken into account
|
||||
#define EFFECT_CONFIG_FORMAT 0x0008 // format field must be taken into account
|
||||
#define EFFECT_CONFIG_ACC_MODE 0x0010 // accessMode field must be taken into account
|
||||
#define EFFECT_CONFIG_PROVIDER 0x0020 // bufferProvider field must be taken into account
|
||||
#define EFFECT_CONFIG_ALL (EFFECT_CONFIG_BUFFER | EFFECT_CONFIG_SMP_RATE | \
|
||||
EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT | \
|
||||
EFFECT_CONFIG_ACC_MODE | EFFECT_CONFIG_PROVIDER)
|
||||
|
||||
// effect_config_s structure describes the format of the pCmdData argument of EFFECT_CMD_CONFIGURE command
|
||||
// to configure audio parameters and buffers for effect engine input and output.
|
||||
typedef struct effect_config_s {
|
||||
buffer_config_t inputCfg;
|
||||
buffer_config_t outputCfg;;
|
||||
} effect_config_t;
|
||||
|
||||
// effect_param_s structure describes the format of the pCmdData argument of EFFECT_CMD_SET_PARAM
|
||||
// command and pCmdData and pReplyData of EFFECT_CMD_GET_PARAM command.
|
||||
// psize and vsize represent the actual size of parameter and value.
|
||||
//
|
||||
// NOTE: the start of value field inside the data field is always on a 32 bit boundary:
|
||||
//
|
||||
// +-----------+
|
||||
// | status | sizeof(int)
|
||||
// +-----------+
|
||||
// | psize | sizeof(int)
|
||||
// +-----------+
|
||||
// | vsize | sizeof(int)
|
||||
// +-----------+
|
||||
// | | | |
|
||||
// ~ parameter ~ > psize |
|
||||
// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int)
|
||||
// +-----------+ |
|
||||
// | padding | |
|
||||
// +-----------+
|
||||
// | | |
|
||||
// ~ value ~ > vsize
|
||||
// | | |
|
||||
// +-----------+
|
||||
|
||||
typedef struct effect_param_s {
|
||||
int32_t status; // Transaction status (unused for command, used for reply)
|
||||
uint32_t psize; // Parameter size
|
||||
uint32_t vsize; // Value size
|
||||
char data[]; // Start of Parameter + Value data
|
||||
} effect_param_t;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect library interface
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// An effect library is required to implement and expose the following functions
|
||||
// to enable effect enumeration and instantiation. The name of these functions must be as
|
||||
// specified here as the effect framework will get the function address with dlsym():
|
||||
//
|
||||
// - effect_QueryNumberEffects_t EffectQueryNumberEffects;
|
||||
// - effect_QueryNextEffect_t EffectQueryNext;
|
||||
// - effect_CreateEffect_t EffectCreate;
|
||||
// - effect_ReleaseEffect_t EffectRelease;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectQueryNumberEffects
|
||||
//
|
||||
// Description: Returns the number of different effect exposed by the
|
||||
// library. Each effect must have a unique effect uuid (see
|
||||
// effect_descriptor_t). This function together with EffectQueryNext()
|
||||
// is used to enumerate all effects present in the library.
|
||||
// Each time EffectQueryNumberEffects() is called, the library must
|
||||
// reset the index of the effect descriptor returned by next call to
|
||||
// EffectQueryNext() to restart enumeration from the beginning.
|
||||
//
|
||||
// Input/Output:
|
||||
// pNumEffects: address where the number of effects should be returned.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid pNumEffects
|
||||
// *pNumEffects: updated with number of effects in library
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_QueryNumberEffects_t)(int32_t *pNumEffects);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectQueryNext
|
||||
//
|
||||
// Description: Returns a descriptor of the next available effect.
|
||||
// See effect_descriptor_t for details on effect descriptors.
|
||||
// This function together with EffectQueryNext() is used to enumerate all
|
||||
// effects present in the library. The enumeration sequence is:
|
||||
// EffectQueryNumberEffects(&num_effects);
|
||||
// while (num_effects--)
|
||||
// EffectQueryNext();
|
||||
//
|
||||
// Input/Output:
|
||||
// pDescriptor: address where to return the effect descriptor.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid pDescriptor
|
||||
// -ENOENT no more effect available
|
||||
// *pDescriptor: updated with the effect descriptor.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_QueryNextEffect_t)(effect_descriptor_t *pDescriptor);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectCreate
|
||||
//
|
||||
// Description: Creates an effect engine of the specified type and returns an
|
||||
// effect control interface on this engine. The function will allocate the
|
||||
// resources for an instance of the requested effect engine and return
|
||||
// a handle on the effect control interface.
|
||||
//
|
||||
// Input:
|
||||
// pEffectUuid: pointer to the effect uuid.
|
||||
//
|
||||
// Input/Output:
|
||||
// pInterface: address where to return the effect interface.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid pEffectUuid or pInterface
|
||||
// -ENOENT No effect with this uuid found
|
||||
// *pInterface: updated with the effect interface handle.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_CreateEffect_t)(effect_uuid_t *uuid, effect_interface_t *pInterface);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectRelease
|
||||
//
|
||||
// Description: Releases the effect engine whose handle is given as argument.
|
||||
// All resources allocated to this particular instance of the effect are
|
||||
// released.
|
||||
//
|
||||
// Input:
|
||||
// interface: handle on the effect interface to be released.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid interface handle
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_ReleaseEffect_t)(effect_interface_t interface);
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_EFFECTAPI_H_*/
|
50
include/media/EffectEqualizerApi.h
Normal file
50
include/media/EffectEqualizerApi.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTEQUALIZERAPI_H_
|
||||
#define ANDROID_EFFECTEQUALIZERAPI_H_
|
||||
|
||||
#include <media/EffectApi.h>
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//TODO replace by openSL ES include when available
|
||||
static const effect_uuid_t SL_IID_EQUALIZER_ = { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
|
||||
const effect_uuid_t * const SL_IID_EQUALIZER = &SL_IID_EQUALIZER_;
|
||||
|
||||
/* enumerated parameters for Equalizer effect */
|
||||
typedef enum
|
||||
{
|
||||
EQ_PARAM_NUM_BANDS, // Gets the number of frequency bands that the equalizer supports.
|
||||
EQ_PARAM_LEVEL_RANGE, // Returns the minimum and maximum band levels supported.
|
||||
EQ_PARAM_BAND_LEVEL, // Gets/Sets the gain set for the given equalizer band.
|
||||
EQ_PARAM_CENTER_FREQ, // Gets the center frequency of the given band.
|
||||
EQ_PARAM_BAND_FREQ_RANGE, // Gets the frequency range of the given frequency band.
|
||||
EQ_PARAM_GET_BAND, // Gets the band that has the most effect on the given frequency.
|
||||
EQ_PARAM_CUR_PRESET, // Gets/Sets the current preset.
|
||||
EQ_PARAM_GET_NUM_OF_PRESETS, // Gets the total number of presets the equalizer supports.
|
||||
EQ_PARAM_GET_PRESET_NAME // Gets the preset name based on the index.
|
||||
} t_equalizer_params;
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_EFFECTEQUALIZERAPI_H_*/
|
214
include/media/EffectFactoryApi.h
Normal file
214
include/media/EffectFactoryApi.h
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTFACTORYAPI_H_
|
||||
#define ANDROID_EFFECTFACTORYAPI_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <media/EffectApi.h>
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect factory interface
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectQueryNumberEffects
|
||||
//
|
||||
// Description: Returns the number of different effect in all loaded libraries.
|
||||
// Each effect must have a different effect uuid (see
|
||||
// effect_descriptor_t). This function together with EffectQueryNext()
|
||||
// is used to enumerate all effects present in all loaded libraries.
|
||||
// Each time EffectQueryNumberEffects() is called, the factory must
|
||||
// reset the index of the effect descriptor returned by next call to
|
||||
// EffectQueryNext() to restart enumeration from the beginning.
|
||||
//
|
||||
// Input/Output:
|
||||
// pNumEffects: address where the number of effects should be returned.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV factory failed to initialize
|
||||
// -EINVAL invalid pNumEffects
|
||||
// *pNumEffects: updated with number of effects in factory
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectQueryNumberEffects(int *pNumEffects);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectQueryNext
|
||||
//
|
||||
// Description: Returns a descriptor of the next available effect.
|
||||
// See effect_descriptor_t for a details on effect descriptor.
|
||||
// This function together with EffectQueryNext() is used to enumerate all
|
||||
// effects present in all loaded libraries. The enumeration sequence is:
|
||||
// EffectQueryNumberEffects(&num_effects);
|
||||
// while (num_effects--)
|
||||
// EffectQueryNext();
|
||||
//
|
||||
// Input/Output:
|
||||
// pDescriptor: address where to return the effect descriptor.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV factory failed to initialize
|
||||
// -EINVAL invalid pDescriptor
|
||||
// -ENOENT no more effect available
|
||||
// *pDescriptor: updated with the effect descriptor.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectQueryNext(effect_descriptor_t *pDescriptor);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectCreate
|
||||
//
|
||||
// Description: Creates an effect engine of the specified type and returns an
|
||||
// effect control interface on this engine. The function will allocate the
|
||||
// resources for an instance of the requested effect engine and return
|
||||
// a handler on the effect control interface.
|
||||
//
|
||||
// Input:
|
||||
// pEffectUuid: pointer to the effect uuid.
|
||||
//
|
||||
// Input/Output:
|
||||
// pInterface: address where to return the effect interface.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV factory failed to initialize
|
||||
// -EINVAL invalid pEffectUuid or pInterface
|
||||
// -ENOENT No effect with this uuid found
|
||||
// *pInterface: updated with the effect interface.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectCreate(effect_uuid_t *pEffectUuid, effect_interface_t *pInterface);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectRelease
|
||||
//
|
||||
// Description: Releases the effect engine whose handler is given as argument.
|
||||
// All resources allocated to this particular instance of the effect are
|
||||
// released.
|
||||
//
|
||||
// Input:
|
||||
// interface: handler on the effect interface to be released.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV factory failed to initialize
|
||||
// -EINVAL invalid interface handler
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectRelease(effect_interface_t interface);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectLoadLibrary
|
||||
//
|
||||
// Description: Loads the effect library which path is given as first argument.
|
||||
// This must be the full path of a dynamic library (.so) implementing one or
|
||||
// more effect engines and exposing the effect library interface described in
|
||||
// EffectApi.h. The function returns a handle on the library for used by
|
||||
// further call to EffectUnloadLibrary() to unload the library.
|
||||
//
|
||||
// Input:
|
||||
// libPath: full path of the dynamic library file in the file system.
|
||||
//
|
||||
// handle: address where to return the library handle
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV Effect factory not initialized or
|
||||
// library could not be loaded or
|
||||
// library does not implement required functions
|
||||
// -EINVAL invalid libPath string or handle
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectLoadLibrary(const char *libPath, int *handle);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectUnloadLibrary
|
||||
//
|
||||
// Description: Unloads the effect library which handle is given as argument.
|
||||
//
|
||||
// Input:
|
||||
// handle: library handle
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV Effect factory not initialized
|
||||
// -ENOENT invalid handle
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectUnloadLibrary(int handle);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectGetDescriptor
|
||||
//
|
||||
// Description: Returns the descriptor of the effect which uuid is pointed
|
||||
// to by first argument.
|
||||
//
|
||||
// Input:
|
||||
// pEffectUuid: pointer to the effect uuid.
|
||||
//
|
||||
// Input/Output:
|
||||
// pDescriptor: address where to return the effect descriptor.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV factory failed to initialize
|
||||
// -EINVAL invalid pEffectUuid or pDescriptor
|
||||
// -ENOENT No effect with this uuid found
|
||||
// *pDescriptor: updated with the effect descriptor.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectGetDescriptor(effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectIsNullUuid
|
||||
//
|
||||
// Description: Helper function to compare effect uuid to EFFECT_UUID_NULL
|
||||
//
|
||||
// Input:
|
||||
// pEffectUuid: pointer to effect uuid to compare to EFFECT_UUID_NULL.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 if uuid is different from EFFECT_UUID_NULL.
|
||||
// 1 if uuid is equal to EFFECT_UUID_NULL.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int EffectIsNullUuid(effect_uuid_t *pEffectUuid);
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_EFFECTFACTORYAPI_H_*/
|
82
include/media/EffectReverbApi.h
Normal file
82
include/media/EffectReverbApi.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTREVERBAPI_H_
|
||||
#define ANDROID_EFFECTREVERBAPI_H_
|
||||
|
||||
#include <media/EffectApi.h>
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// TODO: include OpenSLES_IID.h instead
|
||||
static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
|
||||
const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
|
||||
|
||||
static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
|
||||
const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
|
||||
|
||||
/* enumerated parameter settings for Reverb effect */
|
||||
typedef enum
|
||||
{
|
||||
REVERB_PARAM_BYPASS,
|
||||
REVERB_PARAM_PRESET,
|
||||
// Parameters below are as defined in OpenSL ES specification for environmental reverb interface
|
||||
REVERB_PARAM_ROOM_LEVEL, // in millibels, range -6000 to 0
|
||||
REVERB_PARAM_ROOM_HF_LEVEL, // in millibels, range -4000 to 0
|
||||
REVERB_PARAM_DECAY_TIME, // in milliseconds, range 100 to 20000
|
||||
REVERB_PARAM_DECAY_HF_RATIO, // in permilles, range 100 to 1000
|
||||
REVERB_PARAM_REFLECTIONS_LEVEL, // in millibels, range -6000 to 0
|
||||
REVERB_PARAM_REFLECTIONS_DELAY, // in milliseconds, range 0 to 65
|
||||
REVERB_PARAM_REVERB_LEVEL, // in millibels, range -6000 to 0
|
||||
REVERB_PARAM_REVERB_DELAY, // in milliseconds, range 0 to 65
|
||||
REVERB_PARAM_DIFFUSION, // in permilles, range 0 to 1000
|
||||
REVERB_PARAM_DENSITY, // in permilles, range 0 to 1000
|
||||
REVERB_PARAM_PROPERTIES
|
||||
} t_reverb_params;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REVERB_PRESET_LARGE_HALL,
|
||||
REVERB_PRESET_HALL,
|
||||
REVERB_PRESET_CHAMBER,
|
||||
REVERB_PRESET_ROOM,
|
||||
} t_reverb_presets;
|
||||
|
||||
//t_reverb_properties is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
|
||||
typedef struct s_reverb_properties {
|
||||
int16_t roomLevel;
|
||||
int16_t roomHFLevel;
|
||||
int32_t decayTime;
|
||||
int16_t decayHFRatio;
|
||||
int16_t reflectionsLevel;
|
||||
int32_t reflectionsDelay;
|
||||
int32_t reverbDelay;
|
||||
int16_t reverbLevel;
|
||||
int16_t diffusion;
|
||||
int16_t density;
|
||||
int16_t padding;
|
||||
} t_reverb_properties;
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_EFFECTREVERBAPI_H_*/
|
90
media/libeffects/Android.mk
Normal file
90
media/libeffects/Android.mk
Normal file
@ -0,0 +1,90 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# Effect factory library
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
EffectsFactory.c
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
|
||||
LOCAL_MODULE:= libeffects
|
||||
|
||||
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
|
||||
LOCAL_LDLIBS += -ldl
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
# Default Reverb library
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
EffectReverb.c.arm \
|
||||
EffectsMath.c.arm
|
||||
LOCAL_CFLAGS+= -O2
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
|
||||
LOCAL_MODULE:= libreverb
|
||||
|
||||
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
|
||||
LOCAL_LDLIBS += -ldl
|
||||
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)
|
||||
|
||||
# Default Equalizer library
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
EffectsMath.c.arm \
|
||||
EffectEqualizer.cpp \
|
||||
AudioBiquadFilter.cpp.arm \
|
||||
AudioCoefInterpolator.cpp.arm \
|
||||
AudioPeakingFilter.cpp.arm \
|
||||
AudioShelvingFilter.cpp.arm \
|
||||
AudioEqualizer.cpp.arm
|
||||
|
||||
LOCAL_CFLAGS+= -O2
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
|
||||
LOCAL_MODULE:= libequalizer
|
||||
|
||||
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
|
||||
LOCAL_LDLIBS += -ldl
|
||||
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)
|
260
media/libeffects/AudioBiquadFilter.cpp
Normal file
260
media/libeffects/AudioBiquadFilter.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
/* //device/servers/AudioFlinger/AudioBiquadFilter.cpp
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "AudioBiquadFilter.h"
|
||||
|
||||
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
|
||||
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
|
||||
|
||||
namespace android {
|
||||
|
||||
const audio_coef_t AudioBiquadFilter::IDENTITY_COEFS[AudioBiquadFilter::NUM_COEFS] = { AUDIO_COEF_ONE, 0, 0, 0, 0 };
|
||||
|
||||
AudioBiquadFilter::AudioBiquadFilter(int nChannels, int sampleRate) {
|
||||
configure(nChannels, sampleRate);
|
||||
reset();
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::configure(int nChannels, int sampleRate) {
|
||||
assert(nChannels > 0 && nChannels <= MAX_CHANNELS);
|
||||
assert(sampleRate > 0);
|
||||
mNumChannels = nChannels;
|
||||
mMaxDelta = static_cast<int64_t>(MAX_DELTA_PER_SEC)
|
||||
* AUDIO_COEF_ONE
|
||||
/ sampleRate;
|
||||
clear();
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::reset() {
|
||||
memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
|
||||
mCoefDirtyBits = 0;
|
||||
setState(STATE_BYPASS);
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::clear() {
|
||||
memset(mDelays, 0, sizeof(mDelays));
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate) {
|
||||
memcpy(mTargetCoefs, coefs, sizeof(mTargetCoefs));
|
||||
if (mState & STATE_ENABLED_MASK) {
|
||||
if (UNLIKELY(immediate)) {
|
||||
memcpy(mCoefs, coefs, sizeof(mCoefs));
|
||||
setState(STATE_NORMAL);
|
||||
} else {
|
||||
setState(STATE_TRANSITION_TO_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process(const audio_sample_t in[], audio_sample_t out[],
|
||||
int frameCount) {
|
||||
(this->*mCurProcessFunc)(in, out, frameCount);
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::enable(bool immediate) {
|
||||
if (UNLIKELY(immediate)) {
|
||||
memcpy(mCoefs, mTargetCoefs, sizeof(mCoefs));
|
||||
setState(STATE_NORMAL);
|
||||
} else {
|
||||
setState(STATE_TRANSITION_TO_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::disable(bool immediate) {
|
||||
if (UNLIKELY(immediate)) {
|
||||
memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
|
||||
setState(STATE_BYPASS);
|
||||
} else {
|
||||
setState(STATE_TRANSITION_TO_BYPASS);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::setState(state_t state) {
|
||||
switch (state) {
|
||||
case STATE_BYPASS:
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_bypass;
|
||||
break;
|
||||
case STATE_TRANSITION_TO_BYPASS:
|
||||
if (mNumChannels == 1) {
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_mono;
|
||||
} else {
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_multi;
|
||||
}
|
||||
mCoefDirtyBits = (1 << NUM_COEFS) - 1;
|
||||
break;
|
||||
case STATE_TRANSITION_TO_NORMAL:
|
||||
if (mNumChannels == 1) {
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_mono;
|
||||
} else {
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_multi;
|
||||
}
|
||||
mCoefDirtyBits = (1 << NUM_COEFS) - 1;
|
||||
break;
|
||||
case STATE_NORMAL:
|
||||
if (mNumChannels == 1) {
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_normal_mono;
|
||||
} else {
|
||||
mCurProcessFunc = &AudioBiquadFilter::process_normal_multi;
|
||||
}
|
||||
break;
|
||||
}
|
||||
mState = state;
|
||||
}
|
||||
|
||||
bool AudioBiquadFilter::updateCoefs(const audio_coef_t coefs[NUM_COEFS],
|
||||
int frameCount) {
|
||||
int64_t maxDelta = mMaxDelta * frameCount;
|
||||
for (int i = 0; i < NUM_COEFS; ++i) {
|
||||
if (mCoefDirtyBits & (1<<i)) {
|
||||
audio_coef_t diff = coefs[i] - mCoefs[i];
|
||||
if (diff > maxDelta) {
|
||||
mCoefs[i] += maxDelta;
|
||||
} else if (diff < -maxDelta) {
|
||||
mCoefs[i] -= maxDelta;
|
||||
} else {
|
||||
mCoefs[i] = coefs[i];
|
||||
mCoefDirtyBits ^= (1<<i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mCoefDirtyBits == 0;
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_bypass(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
// The common case is in-place processing, because this is what the EQ does.
|
||||
if (UNLIKELY(in != out)) {
|
||||
memcpy(out, in, frameCount * mNumChannels * sizeof(audio_sample_t));
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_normal_mono(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
size_t nFrames = frameCount;
|
||||
audio_sample_t x1 = mDelays[0][0];
|
||||
audio_sample_t x2 = mDelays[0][1];
|
||||
audio_sample_t y1 = mDelays[0][2];
|
||||
audio_sample_t y2 = mDelays[0][3];
|
||||
const audio_coef_t b0 = mCoefs[0];
|
||||
const audio_coef_t b1 = mCoefs[1];
|
||||
const audio_coef_t b2 = mCoefs[2];
|
||||
const audio_coef_t a1 = mCoefs[3];
|
||||
const audio_coef_t a2 = mCoefs[4];
|
||||
while (nFrames-- > 0) {
|
||||
audio_sample_t x0 = *(in++);
|
||||
audio_coef_sample_acc_t acc;
|
||||
acc = mul_coef_sample(b0, x0);
|
||||
acc = mac_coef_sample(b1, x1, acc);
|
||||
acc = mac_coef_sample(b2, x2, acc);
|
||||
acc = mac_coef_sample(a1, y1, acc);
|
||||
acc = mac_coef_sample(a2, y2, acc);
|
||||
audio_sample_t y0 = coef_sample_acc_to_sample(acc);
|
||||
y2 = y1;
|
||||
y1 = y0;
|
||||
x2 = x1;
|
||||
x1 = x0;
|
||||
(*out++) = y0;
|
||||
}
|
||||
mDelays[0][0] = x1;
|
||||
mDelays[0][1] = x2;
|
||||
mDelays[0][2] = y1;
|
||||
mDelays[0][3] = y2;
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_transition_normal_mono(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
if (updateCoefs(mTargetCoefs, frameCount)) {
|
||||
setState(STATE_NORMAL);
|
||||
}
|
||||
process_normal_mono(in, out, frameCount);
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_transition_bypass_mono(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
if (updateCoefs(IDENTITY_COEFS, frameCount)) {
|
||||
setState(STATE_NORMAL);
|
||||
}
|
||||
process_normal_mono(in, out, frameCount);
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_normal_multi(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
const audio_coef_t b0 = mCoefs[0];
|
||||
const audio_coef_t b1 = mCoefs[1];
|
||||
const audio_coef_t b2 = mCoefs[2];
|
||||
const audio_coef_t a1 = mCoefs[3];
|
||||
const audio_coef_t a2 = mCoefs[4];
|
||||
for (int ch = 0; ch < mNumChannels; ++ch) {
|
||||
size_t nFrames = frameCount;
|
||||
audio_sample_t x1 = mDelays[ch][0];
|
||||
audio_sample_t x2 = mDelays[ch][1];
|
||||
audio_sample_t y1 = mDelays[ch][2];
|
||||
audio_sample_t y2 = mDelays[ch][3];
|
||||
while (nFrames-- > 0) {
|
||||
audio_sample_t x0 = *in;
|
||||
audio_coef_sample_acc_t acc;
|
||||
acc = mul_coef_sample(b0, x0);
|
||||
acc = mac_coef_sample(b1, x1, acc);
|
||||
acc = mac_coef_sample(b2, x2, acc);
|
||||
acc = mac_coef_sample(a1, y1, acc);
|
||||
acc = mac_coef_sample(a2, y2, acc);
|
||||
audio_sample_t y0 = coef_sample_acc_to_sample(acc);
|
||||
y2 = y1;
|
||||
y1 = y0;
|
||||
x2 = x1;
|
||||
x1 = x0;
|
||||
*out = y0;
|
||||
in += mNumChannels;
|
||||
out += mNumChannels;
|
||||
}
|
||||
mDelays[ch][0] = x1;
|
||||
mDelays[ch][1] = x2;
|
||||
mDelays[ch][2] = y1;
|
||||
mDelays[ch][3] = y2;
|
||||
in -= frameCount * mNumChannels - 1;
|
||||
out -= frameCount * mNumChannels - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_transition_normal_multi(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
if (updateCoefs(mTargetCoefs, frameCount)) {
|
||||
setState(STATE_NORMAL);
|
||||
}
|
||||
process_normal_multi(in, out, frameCount);
|
||||
}
|
||||
|
||||
void AudioBiquadFilter::process_transition_bypass_multi(const audio_sample_t * in,
|
||||
audio_sample_t * out,
|
||||
int frameCount) {
|
||||
if (updateCoefs(IDENTITY_COEFS, frameCount)) {
|
||||
setState(STATE_NORMAL);
|
||||
}
|
||||
process_normal_multi(in, out, frameCount);
|
||||
}
|
||||
|
||||
}
|
180
media/libeffects/AudioBiquadFilter.h
Normal file
180
media/libeffects/AudioBiquadFilter.h
Normal file
@ -0,0 +1,180 @@
|
||||
/* //device/include/server/AudioFlinger/AudioBiquadFilter.h
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIO_BIQUAD_FILTER_H
|
||||
#define ANDROID_AUDIO_BIQUAD_FILTER_H
|
||||
|
||||
#include "AudioCommon.h"
|
||||
|
||||
namespace android {
|
||||
// A biquad filter.
|
||||
// Implements the recursion y[n]=a0*y[n-1]+a1*y[n-2]+b0*x[n]+b1*x[n-1]+b2*x[n-2]
|
||||
// (the a0 and a1 coefficients have an opposite sign to the common convention)
|
||||
// The filter works on fixed sized blocks of data (frameCount multi-channel
|
||||
// samples, as defined during construction). An arbitrary number of interlaced
|
||||
// channels is supported.
|
||||
// Filter can operate in an enabled (active) or disabled (bypassed) states.
|
||||
// A mechanism for suppression of artifacts caused by abrupt coefficient changes
|
||||
// is implemented: normally, when the enable(), disable() and setCoefs() methods
|
||||
// are called without the immediate flag set, the filter smoothly transitions
|
||||
// from its current state to the desired state.
|
||||
class AudioBiquadFilter {
|
||||
public:
|
||||
// Max number of channels (can be changed here, and everything should work).
|
||||
static const int MAX_CHANNELS = 2;
|
||||
// Number of coefficients.
|
||||
static const int NUM_COEFS = 5;
|
||||
|
||||
// Constructor.
|
||||
// nChannels Number of input/output channels.
|
||||
// sampleRate Sample rate, in Hz.
|
||||
AudioBiquadFilter(int nChannels, int sampleRate);
|
||||
|
||||
// Reconfiguration of the filter. Implies clear().
|
||||
// nChannels Number of input/output channels.
|
||||
// sampleRate Sample rate, in Hz.
|
||||
void configure(int nChannels, int sampleRate);
|
||||
|
||||
// Resets the internal state of the filter.
|
||||
// Coefficients are reset to identity, state becomes disabled. This change
|
||||
// happens immediately and might cause discontinuities in the output.
|
||||
// Delay lines are not cleared.
|
||||
void reset();
|
||||
|
||||
// Clears the delay lines.
|
||||
// This change happens immediately and might cause discontinuities in the
|
||||
// output.
|
||||
void clear();
|
||||
|
||||
// Sets the coefficients.
|
||||
// If called when filter is disabled, will have no immediate effect, but the
|
||||
// new coefficients will be set and used next time the filter is enabled.
|
||||
// coefs The new coefficients.
|
||||
// immediate If true, transitions to new coefficients smoothly, without
|
||||
// introducing discontinuities in the output. Otherwise,
|
||||
// transitions immediately.
|
||||
void setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate = false);
|
||||
|
||||
// Process a buffer of data. Always processes frameCount multi-channel
|
||||
// samples. Processing can be done in-place, by passing the same buffer as
|
||||
// both arguments.
|
||||
// in The input buffer. Should be of size frameCount * nChannels.
|
||||
// out The output buffer. Should be of size frameCount * nChannels.
|
||||
// frameCount Number of multi-channel samples to process.
|
||||
void process(const audio_sample_t in[], audio_sample_t out[],
|
||||
int frameCount);
|
||||
|
||||
// Enables (activates) the filter.
|
||||
// immediate If true, transitions to new state smoothly, without
|
||||
// introducing discontinuities in the output. Otherwise,
|
||||
// transitions immediately.
|
||||
void enable(bool immediate = false);
|
||||
|
||||
// Disables (bypasses) the filter.
|
||||
// immediate If true, transitions to new state smoothly, without
|
||||
// introducing discontinuities in the output. Otherwise,
|
||||
// transitions immediately.
|
||||
void disable(bool immediate = false);
|
||||
|
||||
private:
|
||||
// A prototype of the actual processing function. Has the same semantics as
|
||||
// the process() method.
|
||||
typedef void (AudioBiquadFilter::*process_func)(const audio_sample_t[],
|
||||
audio_sample_t[],
|
||||
int frameCount);
|
||||
|
||||
// The maximum rate of coefficient change, measured in coefficient units per
|
||||
// second.
|
||||
static const audio_coef_t MAX_DELTA_PER_SEC = 2000;
|
||||
|
||||
// Coefficients of identity transformation.
|
||||
static const audio_coef_t IDENTITY_COEFS[NUM_COEFS];
|
||||
|
||||
// Filter state.
|
||||
enum state_t {
|
||||
// Bypass.
|
||||
STATE_BYPASS = 0x01,
|
||||
// In the process of smooth transition to bypass state.
|
||||
STATE_TRANSITION_TO_BYPASS = 0x02,
|
||||
// In the process of smooth transition to normal (enabled) state.
|
||||
STATE_TRANSITION_TO_NORMAL = 0x04,
|
||||
// In normal (enabled) state.
|
||||
STATE_NORMAL = 0x05,
|
||||
// A bit-mask for determining whether the filter is enabled or disabled
|
||||
// in the eyes of the client.
|
||||
STATE_ENABLED_MASK = 0x04
|
||||
};
|
||||
|
||||
// Number of channels.
|
||||
int mNumChannels;
|
||||
// Current state.
|
||||
state_t mState;
|
||||
// Maximum coefficient delta per sample.
|
||||
audio_coef_t mMaxDelta;
|
||||
|
||||
// A bit-mask designating for which coefficients the current value is not
|
||||
// necessarily identical to the target value (since we're in transition
|
||||
// state).
|
||||
uint32_t mCoefDirtyBits;
|
||||
// The current coefficients.
|
||||
audio_coef_t mCoefs[NUM_COEFS];
|
||||
// The target coefficients. Will not be identical to mCoefs if we are in a
|
||||
// transition state.
|
||||
audio_coef_t mTargetCoefs[NUM_COEFS];
|
||||
|
||||
// The delay lines.
|
||||
audio_sample_t mDelays[MAX_CHANNELS][4];
|
||||
|
||||
// Current processing function (determines according to current state and
|
||||
// number of channels).
|
||||
process_func mCurProcessFunc;
|
||||
|
||||
// Sets a new state. Updates the processing function accordingly, and sets
|
||||
// the dirty bits if changing to a transition state.
|
||||
void setState(state_t state);
|
||||
|
||||
// In a transition state, modifies the current coefs towards the passed
|
||||
// coefs, while keeping a smooth change rate. Whenever a coef reaches its
|
||||
// target value, the dirty bit is cleared. If all are clear, the function
|
||||
// returns true, and we can then change to our target state.
|
||||
bool updateCoefs(const audio_coef_t coefs[NUM_COEFS], int frameCount);
|
||||
|
||||
// Processing function when in disabled state.
|
||||
void process_bypass(const audio_sample_t * in, audio_sample_t * out,
|
||||
int frameCount);
|
||||
// Processing function when in normal state, mono.
|
||||
void process_normal_mono(const audio_sample_t * in, audio_sample_t * out,
|
||||
int frameCount);
|
||||
// Processing function when transitioning to normal state, mono.
|
||||
void process_transition_normal_mono(const audio_sample_t * in,
|
||||
audio_sample_t * out, int frameCount);
|
||||
// Processing function when transitioning to bypass state, mono.
|
||||
void process_transition_bypass_mono(const audio_sample_t * in,
|
||||
audio_sample_t * out, int frameCount);
|
||||
// Processing function when in normal state, multi-channel.
|
||||
void process_normal_multi(const audio_sample_t * in, audio_sample_t * out,
|
||||
int frameCount);
|
||||
// Processing function when transitioning to normal state, multi-channel.
|
||||
void process_transition_normal_multi(const audio_sample_t * in,
|
||||
audio_sample_t * out, int frameCount);
|
||||
// Processing function when transitioning to bypass state, multi-channel.
|
||||
void process_transition_bypass_multi(const audio_sample_t * in,
|
||||
audio_sample_t * out, int frameCount);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ANDROID_AUDIO_BIQUAD_FILTER_H
|
84
media/libeffects/AudioCoefInterpolator.cpp
Normal file
84
media/libeffects/AudioCoefInterpolator.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/* //device/servers/AudioFlinger/AudioCoefInterpolator.cpp
|
||||
**
|
||||
** Copyright 2008, 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "AudioCoefInterpolator.h"
|
||||
|
||||
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
|
||||
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
|
||||
|
||||
namespace android {
|
||||
|
||||
AudioCoefInterpolator::AudioCoefInterpolator(size_t nInDims,
|
||||
const size_t inDims[],
|
||||
size_t nOutDims,
|
||||
const audio_coef_t * table) {
|
||||
mNumInDims = nInDims;
|
||||
memcpy(mInDims, inDims, nInDims * sizeof(size_t));
|
||||
mNumOutDims = nOutDims;
|
||||
mTable = table;
|
||||
// Initialize offsets array
|
||||
size_t dim = nInDims - 1;
|
||||
mInDimOffsets[nInDims - 1] = nOutDims;
|
||||
while (dim-- > 0) {
|
||||
mInDimOffsets[dim] = mInDimOffsets[dim + 1] * mInDims[dim + 1];
|
||||
}
|
||||
}
|
||||
|
||||
void AudioCoefInterpolator::getCoef(const int intCoord[], uint32_t fracCoord[],
|
||||
audio_coef_t out[]) {
|
||||
size_t index = 0;
|
||||
size_t dim = mNumInDims;
|
||||
while (dim-- > 0) {
|
||||
if (UNLIKELY(intCoord[dim] < 0)) {
|
||||
fracCoord[dim] = 0;
|
||||
} else if (UNLIKELY(intCoord[dim] >= mInDims[dim] - 1)) {
|
||||
fracCoord[dim] = 0;
|
||||
index += mInDimOffsets[dim] * (mInDims[dim] - 1);
|
||||
} else {
|
||||
index += mInDimOffsets[dim] * intCoord[dim];
|
||||
}
|
||||
}
|
||||
getCoefRecurse(index, fracCoord, out, 0);
|
||||
}
|
||||
|
||||
void AudioCoefInterpolator::getCoefRecurse(size_t index,
|
||||
const uint32_t fracCoord[],
|
||||
audio_coef_t out[], size_t dim) {
|
||||
if (dim == mNumInDims) {
|
||||
memcpy(out, mTable + index, mNumOutDims * sizeof(audio_coef_t));
|
||||
} else {
|
||||
getCoefRecurse(index, fracCoord, out, dim + 1);
|
||||
if (LIKELY(fracCoord != 0)) {
|
||||
audio_coef_t tempCoef[MAX_OUT_DIMS];
|
||||
getCoefRecurse(index + mInDimOffsets[dim], fracCoord, tempCoef,
|
||||
dim + 1);
|
||||
size_t d = mNumOutDims;
|
||||
while (d-- > 0) {
|
||||
out[d] = interp(out[d], tempCoef[d], fracCoord[dim]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio_coef_t AudioCoefInterpolator::interp(audio_coef_t lo, audio_coef_t hi,
|
||||
uint32_t frac) {
|
||||
int64_t delta = static_cast<int64_t>(hi-lo) * frac;
|
||||
return lo + static_cast<audio_coef_t> (delta >> 32);
|
||||
}
|
||||
|
||||
}
|
98
media/libeffects/AudioCoefInterpolator.h
Normal file
98
media/libeffects/AudioCoefInterpolator.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* //device/include/server/AudioFlinger/AudioCoefInterpolator.h
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIO_COEF_INTERPOLATOR_H
|
||||
#define ANDROID_AUDIO_COEF_INTERPOLATOR_H
|
||||
|
||||
#include "AudioCommon.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// A helper class for linear interpolation of N-D -> M-D coefficient tables.
|
||||
// This class provides support for out-of-range indexes.
|
||||
// Details:
|
||||
// The purpose is efficient approximation of a N-dimensional vector to
|
||||
// M-dimensional function. The approximation is based on a table of output
|
||||
// values on a uniform grid of the input values. Values not on the grid are
|
||||
// linearly interpolated.
|
||||
// Access to values are done by specifying input values in table index units,
|
||||
// having an integer and a fractional part, e.g. retrieving a value from index
|
||||
// 1.4 will result in linear interpolation between index 1 and index 2.
|
||||
class AudioCoefInterpolator {
|
||||
public:
|
||||
// Constructor.
|
||||
// nInDims Number of input dimensions (limited to MAX_IN_DIMS).
|
||||
// inDims An array of size nInDims with the size of the table on each
|
||||
// respective dimension.
|
||||
// nOutDims Number of output dimensions (limited to MAX_OUT_DIMS).
|
||||
// table The coefficient table. Should be of size:
|
||||
// inDims[0]*inDims[1]*...*inDims[nInDims-1]*nOutDims, where
|
||||
// func([i,j,k]) = table(i,j,k,:)
|
||||
AudioCoefInterpolator(size_t nInDims, const size_t inDims[],
|
||||
size_t nOutDims, const audio_coef_t * table);
|
||||
|
||||
// Get the value of the approximated function at a given point.
|
||||
// intCoord The integer part of the input value. Should be an array of
|
||||
// size nInDims.
|
||||
// fracCoord The fractional part of the input value. Should be an array
|
||||
// of size nInDims. This value is in 32-bit precision.
|
||||
// out An array for the output value. Should be of size nOutDims.
|
||||
void getCoef(const int intCoord[], uint32_t fracCoord[], audio_coef_t out[]);
|
||||
|
||||
private:
|
||||
// Maximum allowed number of input dimensions.
|
||||
static const size_t MAX_IN_DIMS = 8;
|
||||
// Maximum allowed number of output dimensions.
|
||||
static const size_t MAX_OUT_DIMS = 8;
|
||||
|
||||
// Number of input dimensions.
|
||||
size_t mNumInDims;
|
||||
// Number of input dimensions.
|
||||
size_t mInDims[MAX_IN_DIMS];
|
||||
// The offset between two consecutive indexes of each dimension. This is in
|
||||
// fact a cumulative product of mInDims (done in reverse).
|
||||
size_t mInDimOffsets[MAX_IN_DIMS];
|
||||
// Number of output dimensions.
|
||||
size_t mNumOutDims;
|
||||
// The coefficient table.
|
||||
const audio_coef_t * mTable;
|
||||
|
||||
// A recursive function for getting an interpolated coefficient value.
|
||||
// The recursion depth is the number of input dimensions.
|
||||
// At each step, we fetch two interpolated values of the current dimension,
|
||||
// by two recursive calls to this method for the next dimensions. We then
|
||||
// linearly interpolate these values over the current dimension.
|
||||
// index The linear integer index of the value we need to interpolate.
|
||||
// fracCoord A vector of fractional coordinates for each of the input
|
||||
// dimensions.
|
||||
// out Where the output should be written. Needs to be of size
|
||||
// mNumOutDims.
|
||||
// dim The input dimensions we are currently interpolating. This
|
||||
// value will be increased on recursive calls.
|
||||
void getCoefRecurse(size_t index, const uint32_t fracCoord[],
|
||||
audio_coef_t out[], size_t dim);
|
||||
|
||||
// Scalar interpolation of two data points.
|
||||
// lo The first data point.
|
||||
// hi The second data point.
|
||||
// frac A 32-bit fraction designating the weight of the second point.
|
||||
static audio_coef_t interp(audio_coef_t lo, audio_coef_t hi, uint32_t frac);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ANDROID_AUDIO_COEF_INTERPOLATOR_H
|
92
media/libeffects/AudioCommon.h
Normal file
92
media/libeffects/AudioCommon.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* //device/include/server/AudioFlinger/AudioCommon.h
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIO_COMMON_H
|
||||
#define ANDROID_AUDIO_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Audio coefficient type.
|
||||
typedef int32_t audio_coef_t;
|
||||
// Audio sample type.
|
||||
typedef int32_t audio_sample_t;
|
||||
// Accumulator type for coef x sample.
|
||||
typedef int64_t audio_coef_sample_acc_t;
|
||||
|
||||
// Number of fraction bits for audio coefficient.
|
||||
static const int AUDIO_COEF_PRECISION = 24;
|
||||
// Audio coefficient with the value of 1.0
|
||||
static const audio_coef_t AUDIO_COEF_ONE = 1 << AUDIO_COEF_PRECISION;
|
||||
// Audio coefficient with the value of 0.5
|
||||
static const audio_coef_t AUDIO_COEF_HALF = 1 << (AUDIO_COEF_PRECISION - 1);
|
||||
// Number of fraction bits for audio sample.
|
||||
static const int AUDIO_SAMPLE_PRECISION = 24;
|
||||
// Audio sample with the value of 1.0
|
||||
static const audio_sample_t AUDIO_SAMPLE_ONE = 1 << AUDIO_SAMPLE_PRECISION;
|
||||
|
||||
// TODO: These are just temporary naive implementations of the necessary
|
||||
// arithmetic operations needed for the filter. They should be moved to a more
|
||||
// generic location and implemented more efficiently.
|
||||
|
||||
// Multiply a sample by a coefficient to return an accumulator.
|
||||
inline audio_coef_sample_acc_t mul_coef_sample(audio_coef_t x, audio_sample_t y) {
|
||||
return ((audio_coef_sample_acc_t) (x)) * y;
|
||||
}
|
||||
|
||||
// Multiply and accumulate sample by a coefficient to return an accumulator.
|
||||
inline audio_coef_sample_acc_t mac_coef_sample(audio_coef_t x, audio_sample_t y, audio_coef_sample_acc_t acc) {
|
||||
return acc + ((audio_coef_sample_acc_t) (x)) * y;
|
||||
}
|
||||
|
||||
// Convert a sample-coefficient accumulator to a sample.
|
||||
inline audio_sample_t coef_sample_acc_to_sample(audio_coef_sample_acc_t acc) {
|
||||
if (acc < 0) {
|
||||
acc += AUDIO_COEF_ONE - 1;
|
||||
}
|
||||
return (audio_sample_t) (acc >> AUDIO_COEF_PRECISION);
|
||||
}
|
||||
|
||||
// Convert a S15 sample to audio_sample_t
|
||||
inline audio_sample_t s15_to_audio_sample_t(int16_t s15) {
|
||||
return audio_sample_t(s15) << 9;
|
||||
}
|
||||
|
||||
// Convert a audio_sample_t sample to S15 (no clipping)
|
||||
inline int16_t audio_sample_t_to_s15(audio_sample_t sample) {
|
||||
return int16_t((sample + (1 << 8)) >> 9);
|
||||
}
|
||||
|
||||
// Convert a audio_sample_t sample to S15 (with clipping)
|
||||
inline int16_t audio_sample_t_to_s15_clip(audio_sample_t sample) {
|
||||
// TODO: optimize for targets supporting this as an atomic operation.
|
||||
if (__builtin_expect(sample >= (0x7FFF << 9), 0)) {
|
||||
return 0x7FFF;
|
||||
} else if (__builtin_expect(sample <= -(0x8000 << 9), 0)) {
|
||||
return 0x8000;
|
||||
} else {
|
||||
return audio_sample_t_to_s15(sample);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
#endif // ANDROID_AUDIO_COMMON_H
|
315
media/libeffects/AudioEqualizer.cpp
Normal file
315
media/libeffects/AudioEqualizer.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright 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 "AudioEqualizer"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "AudioEqualizer.h"
|
||||
#include "AudioPeakingFilter.h"
|
||||
#include "AudioShelvingFilter.h"
|
||||
#include "EffectsMath.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
size_t AudioEqualizer::GetInstanceSize(int nBands) {
|
||||
assert(nBands >= 2);
|
||||
return sizeof(AudioEqualizer) +
|
||||
sizeof(AudioShelvingFilter) * 2 +
|
||||
sizeof(AudioPeakingFilter) * (nBands - 2);
|
||||
}
|
||||
|
||||
AudioEqualizer * AudioEqualizer::CreateInstance(void * pMem, int nBands,
|
||||
int nChannels, int sampleRate,
|
||||
const PresetConfig * presets,
|
||||
int nPresets) {
|
||||
LOGV("AudioEqualizer::CreateInstance(pMem=%p, nBands=%d, nChannels=%d, "
|
||||
"sampleRate=%d, nPresets=%d)",
|
||||
pMem, nBands, nChannels, sampleRate, nPresets);
|
||||
assert(nBands >= 2);
|
||||
bool ownMem = false;
|
||||
if (pMem == NULL) {
|
||||
pMem = malloc(GetInstanceSize(nBands));
|
||||
if (pMem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ownMem = true;
|
||||
}
|
||||
return new (pMem) AudioEqualizer(pMem, nBands, nChannels, sampleRate,
|
||||
ownMem, presets, nPresets);
|
||||
}
|
||||
|
||||
void AudioEqualizer::configure(int nChannels, int sampleRate) {
|
||||
LOGV("AudioEqualizer::configure(nChannels=%d, sampleRate=%d)", nChannels,
|
||||
sampleRate);
|
||||
mpLowShelf->configure(nChannels, sampleRate);
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].configure(nChannels, sampleRate);
|
||||
}
|
||||
mpHighShelf->configure(nChannels, sampleRate);
|
||||
}
|
||||
|
||||
void AudioEqualizer::clear() {
|
||||
LOGV("AudioEqualizer::clear()");
|
||||
mpLowShelf->clear();
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].clear();
|
||||
}
|
||||
mpHighShelf->clear();
|
||||
}
|
||||
|
||||
void AudioEqualizer::free() {
|
||||
LOGV("AudioEqualizer::free()");
|
||||
if (mpMem != NULL) {
|
||||
::free(mpMem);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEqualizer::reset() {
|
||||
LOGV("AudioEqualizer::reset()");
|
||||
const int32_t bottom = Effects_log2(kMinFreq);
|
||||
const int32_t top = Effects_log2(mSampleRate * 500);
|
||||
const int32_t jump = (top - bottom) / (mNumPeaking + 2);
|
||||
int32_t centerFreq = bottom + jump/2;
|
||||
|
||||
mpLowShelf->reset();
|
||||
mpLowShelf->setFrequency(Effects_exp2(centerFreq));
|
||||
centerFreq += jump;
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].reset();
|
||||
mpPeakingFilters[i].setFrequency(Effects_exp2(centerFreq));
|
||||
centerFreq += jump;
|
||||
}
|
||||
mpHighShelf->reset();
|
||||
mpHighShelf->setFrequency(Effects_exp2(centerFreq));
|
||||
commit(true);
|
||||
mCurPreset = PRESET_CUSTOM;
|
||||
}
|
||||
|
||||
void AudioEqualizer::setGain(int band, int32_t millibel) {
|
||||
LOGV("AudioEqualizer::setGain(band=%d, millibel=%d)", band, millibel);
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band == 0) {
|
||||
mpLowShelf->setGain(millibel);
|
||||
} else if (band == mNumPeaking + 1) {
|
||||
mpHighShelf->setGain(millibel);
|
||||
} else {
|
||||
mpPeakingFilters[band - 1].setGain(millibel);
|
||||
}
|
||||
mCurPreset = PRESET_CUSTOM;
|
||||
}
|
||||
|
||||
void AudioEqualizer::setFrequency(int band, uint32_t millihertz) {
|
||||
LOGV("AudioEqualizer::setFrequency(band=%d, millihertz=%d)", band,
|
||||
millihertz);
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band == 0) {
|
||||
mpLowShelf->setFrequency(millihertz);
|
||||
} else if (band == mNumPeaking + 1) {
|
||||
mpHighShelf->setFrequency(millihertz);
|
||||
} else {
|
||||
mpPeakingFilters[band - 1].setFrequency(millihertz);
|
||||
}
|
||||
mCurPreset = PRESET_CUSTOM;
|
||||
}
|
||||
|
||||
void AudioEqualizer::setBandwidth(int band, uint32_t cents) {
|
||||
LOGV("AudioEqualizer::setBandwidth(band=%d, cents=%d)", band, cents);
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band > 0 && band < mNumPeaking + 1) {
|
||||
mpPeakingFilters[band - 1].setBandwidth(cents);
|
||||
mCurPreset = PRESET_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t AudioEqualizer::getGain(int band) const {
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band == 0) {
|
||||
return mpLowShelf->getGain();
|
||||
} else if (band == mNumPeaking + 1) {
|
||||
return mpHighShelf->getGain();
|
||||
} else {
|
||||
return mpPeakingFilters[band - 1].getGain();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AudioEqualizer::getFrequency(int band) const {
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band == 0) {
|
||||
return mpLowShelf->getFrequency();
|
||||
} else if (band == mNumPeaking + 1) {
|
||||
return mpHighShelf->getFrequency();
|
||||
} else {
|
||||
return mpPeakingFilters[band - 1].getFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AudioEqualizer::getBandwidth(int band) const {
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band == 0 || band == mNumPeaking + 1) {
|
||||
return 0;
|
||||
} else {
|
||||
return mpPeakingFilters[band - 1].getBandwidth();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEqualizer::getBandRange(int band, uint32_t & low,
|
||||
uint32_t & high) const {
|
||||
assert(band >= 0 && band < mNumPeaking + 2);
|
||||
if (band == 0) {
|
||||
low = 0;
|
||||
high = mpLowShelf->getFrequency();
|
||||
} else if (band == mNumPeaking + 1) {
|
||||
low = mpHighShelf->getFrequency();
|
||||
high = mSampleRate * 500;
|
||||
} else {
|
||||
mpPeakingFilters[band - 1].getBandRange(low, high);
|
||||
}
|
||||
}
|
||||
|
||||
const char * AudioEqualizer::getPresetName(int preset) const {
|
||||
assert(preset < mNumPresets && preset >= PRESET_CUSTOM);
|
||||
if (preset == PRESET_CUSTOM) {
|
||||
return "Custom";
|
||||
} else {
|
||||
return mpPresets[preset].name;
|
||||
}
|
||||
}
|
||||
|
||||
int AudioEqualizer::getNumPresets() const {
|
||||
return mNumPresets;
|
||||
}
|
||||
|
||||
int AudioEqualizer::getPreset() const {
|
||||
return mCurPreset;
|
||||
}
|
||||
|
||||
void AudioEqualizer::setPreset(int preset) {
|
||||
LOGV("AudioEqualizer::setPreset(preset=%d)", preset);
|
||||
assert(preset < mNumPresets && preset >= 0);
|
||||
const PresetConfig &presetCfg = mpPresets[preset];
|
||||
for (int band = 0; band < (mNumPeaking + 2); ++band) {
|
||||
const BandConfig & bandCfg = presetCfg.bandConfigs[band];
|
||||
setGain(band, bandCfg.gain);
|
||||
setFrequency(band, bandCfg.freq);
|
||||
setBandwidth(band, bandCfg.bandwidth);
|
||||
}
|
||||
mCurPreset = preset;
|
||||
}
|
||||
|
||||
void AudioEqualizer::commit(bool immediate) {
|
||||
LOGV("AudioEqualizer::commit(immediate=%d)", immediate);
|
||||
mpLowShelf->commit(immediate);
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].commit(immediate);
|
||||
}
|
||||
mpHighShelf->commit(immediate);
|
||||
}
|
||||
|
||||
void AudioEqualizer::process(const audio_sample_t * pIn,
|
||||
audio_sample_t * pOut,
|
||||
int frameCount) {
|
||||
// LOGV("AudioEqualizer::process(frameCount=%d)", frameCount);
|
||||
mpLowShelf->process(pIn, pOut, frameCount);
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].process(pIn, pOut, frameCount);
|
||||
}
|
||||
mpHighShelf->process(pIn, pOut, frameCount);
|
||||
}
|
||||
|
||||
void AudioEqualizer::enable(bool immediate) {
|
||||
LOGV("AudioEqualizer::enable(immediate=%d)", immediate);
|
||||
mpLowShelf->enable(immediate);
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].enable(immediate);
|
||||
}
|
||||
mpHighShelf->enable(immediate);
|
||||
}
|
||||
|
||||
void AudioEqualizer::disable(bool immediate) {
|
||||
LOGV("AudioEqualizer::disable(immediate=%d)", immediate);
|
||||
mpLowShelf->disable(immediate);
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
mpPeakingFilters[i].disable(immediate);
|
||||
}
|
||||
mpHighShelf->disable(immediate);
|
||||
}
|
||||
|
||||
int AudioEqualizer::getMostRelevantBand(uint32_t targetFreq) const {
|
||||
// First, find the two bands that the target frequency is between.
|
||||
uint32_t low = mpLowShelf->getFrequency();
|
||||
if (targetFreq <= low) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t high = mpHighShelf->getFrequency();
|
||||
if (targetFreq >= high) {
|
||||
return mNumPeaking + 1;
|
||||
}
|
||||
int band = mNumPeaking;
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
uint32_t freq = mpPeakingFilters[i].getFrequency();
|
||||
if (freq >= targetFreq) {
|
||||
high = freq;
|
||||
band = i;
|
||||
break;
|
||||
}
|
||||
low = freq;
|
||||
}
|
||||
// Now, low is right below the target and high is right above. See which one
|
||||
// is closer on a log scale.
|
||||
low = Effects_log2(low);
|
||||
high = Effects_log2(high);
|
||||
targetFreq = Effects_log2(targetFreq);
|
||||
if (high - targetFreq < targetFreq - low) {
|
||||
return band + 1;
|
||||
} else {
|
||||
return band;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AudioEqualizer::AudioEqualizer(void * pMem, int nBands, int nChannels,
|
||||
int sampleRate, bool ownMem,
|
||||
const PresetConfig * presets, int nPresets)
|
||||
: mSampleRate(sampleRate)
|
||||
, mpPresets(presets)
|
||||
, mNumPresets(nPresets) {
|
||||
assert(pMem != NULL);
|
||||
assert(nPresets == 0 || nPresets > 0 && presets != NULL);
|
||||
mpMem = ownMem ? pMem : NULL;
|
||||
|
||||
pMem = (char *) pMem + sizeof(AudioEqualizer);
|
||||
mpLowShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kLowShelf,
|
||||
nChannels, sampleRate);
|
||||
pMem = (char *) pMem + sizeof(AudioShelvingFilter);
|
||||
mpHighShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kHighShelf,
|
||||
nChannels, sampleRate);
|
||||
pMem = (char *) pMem + sizeof(AudioShelvingFilter);
|
||||
mNumPeaking = nBands - 2;
|
||||
if (mNumPeaking > 0) {
|
||||
mpPeakingFilters = reinterpret_cast<AudioPeakingFilter *>(pMem);
|
||||
for (int i = 0; i < mNumPeaking; ++i) {
|
||||
new (&mpPeakingFilters[i]) AudioPeakingFilter(nChannels,
|
||||
sampleRate);
|
||||
}
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
}
|
246
media/libeffects/AudioEqualizer.h
Normal file
246
media/libeffects/AudioEqualizer.h
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef AUDIOEQUALIZER_H_
|
||||
#define AUDIOEQUALIZER_H_
|
||||
|
||||
#include "AudioCommon.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class AudioShelvingFilter;
|
||||
class AudioPeakingFilter;
|
||||
|
||||
// A parametric audio equalizer. Supports an arbitrary number of bands and
|
||||
// presets.
|
||||
// The EQ is composed of a low-shelf, zero or more peaking filters and a high
|
||||
// shelf, where each band has frequency and gain controls, and the peaking
|
||||
// filters have an additional bandwidth control.
|
||||
class AudioEqualizer {
|
||||
public:
|
||||
// Configuration of a single band.
|
||||
struct BandConfig {
|
||||
// Gain in millibel.
|
||||
int32_t gain;
|
||||
// Frequency in millihertz.
|
||||
uint32_t freq;
|
||||
// Bandwidth in cents (ignored on shelving filters).
|
||||
uint32_t bandwidth;
|
||||
};
|
||||
|
||||
// Preset configuration.
|
||||
struct PresetConfig {
|
||||
// Human-readable name.
|
||||
const char * name;
|
||||
// An array of size nBands where each element is a configuration for the
|
||||
// corresponding band.
|
||||
const BandConfig * bandConfigs;
|
||||
};
|
||||
|
||||
// This value is used when requesting current preset, and EQ is not using a
|
||||
// preset.
|
||||
static const int PRESET_CUSTOM = -1;
|
||||
|
||||
// Get the required memory size for an instance of this class.
|
||||
// nBands Number of bands required in the instance.
|
||||
static size_t GetInstanceSize(int nBands);
|
||||
|
||||
// Create an instance of this class.
|
||||
// If succeeds, a respective call is expected to freeInstance(), regardless
|
||||
// of who owns the context memory.
|
||||
// pMem A memory buffer of at least the size returned by
|
||||
// GetInstanceSize(), where the instance context is to be
|
||||
// stored. If NULL, it will be automatically allocated (using
|
||||
// malloc).
|
||||
// nBands Number of bands. Must be >= 2.
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
// presets The presets configuration. May be NULL, but in that case the
|
||||
// client is required not to call preset-related functions.
|
||||
// This array is owned by the client and is not copied. It
|
||||
// must be kept valid by the client as long as the instance is
|
||||
// alive.
|
||||
// nPresets Number of elements in the presets array.
|
||||
// returns The instance if success. NULL if pMem is NULL and allocation
|
||||
// failed.
|
||||
static AudioEqualizer * CreateInstance(void * pMem, int nBands,
|
||||
int nChannels,
|
||||
int sampleRate,
|
||||
const PresetConfig * presets,
|
||||
int nPresets);
|
||||
|
||||
// Reconfiguration of the filter. Changes input/output format, but does not
|
||||
// alter current parameter values. Causes reset of the delay lines.
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
void configure(int nChannels, int sampleRate);
|
||||
|
||||
// Resets the filter parameters to the following values:
|
||||
// frequency: 0
|
||||
// gain: 0
|
||||
// bandwidth: 1200 cents.
|
||||
// It also disables the filter. Does not clear the delay lines.
|
||||
void reset();
|
||||
|
||||
// Clears delay lines. Does not alter parameter values.
|
||||
void clear();
|
||||
|
||||
// Frees the object. Will free the memory if the object owned it, i.e. if
|
||||
// a NULL pointer was passed to CreateInstance as pMem.
|
||||
void free();
|
||||
|
||||
// Sets gain value. Actual change will only take place upon commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// band The band to set the gain for.
|
||||
// millibel Gain value in millibel (1/100 of decibel).
|
||||
void setGain(int band, int32_t millibel);
|
||||
|
||||
// Gets gain of a certain band. This is always the last value set (or
|
||||
// default value after reset).
|
||||
// band The band to get the gain for.
|
||||
// returns Gain value in millibel (1/100 of decibel).
|
||||
int32_t getGain(int band) const;
|
||||
|
||||
// Sets cutoff frequency value. Actual change will only take place upon
|
||||
// commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// band The band to set the frequency for.
|
||||
// millihertz Frequency value in mHz.
|
||||
void setFrequency(int band, uint32_t millihertz);
|
||||
|
||||
// Gets frequency of a certain band. This is always the last value set (or
|
||||
// default value after reset).
|
||||
// band The band to get the frequency for.
|
||||
// returns Frequency value in mHz.
|
||||
uint32_t getFrequency(int band) const;
|
||||
|
||||
// Sets bandwidth value. Actual change will only take place upon commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// If called on the first or last band, this call is ignored.
|
||||
// band The band to set the frequency for.
|
||||
// cents Bandwidth value in cents (1/1200 octave).
|
||||
void setBandwidth(int band, uint32_t cents);
|
||||
|
||||
// Gets bandwidth of a certain band. This is always the last value set (or
|
||||
// default value after reset). For the first and last bands, 0 is always
|
||||
// returned.
|
||||
// band The band to get the bandwidth for.
|
||||
// returns Bandwidth value in cents (1/1200 octave).
|
||||
uint32_t getBandwidth(int band) const;
|
||||
|
||||
// Gets lower and upper boundaries of a band.
|
||||
// For the low shelf, the low bound is 0 and the high bound is the band
|
||||
// frequency.
|
||||
// For the high shelf, the low bound is the band frequency and the high
|
||||
// bound is Nyquist.
|
||||
// For the peaking filters, they are the gain[dB]/2 points.
|
||||
void getBandRange(int band, uint32_t & low, uint32_t & high) const;
|
||||
|
||||
// Gets a human-readable name for a preset ID. Will return "Custom" if
|
||||
// PRESET_CUSTOM is passed.
|
||||
// preset The preset ID. Must be less than number of presets.
|
||||
const char * getPresetName(int preset) const;
|
||||
|
||||
// Gets the number of presets.
|
||||
int getNumPresets() const;
|
||||
|
||||
// Gets the currently set preset ID.
|
||||
// Will return PRESET_CUSTOM in case the EQ parameters have been modified
|
||||
// manually since a preset was set.
|
||||
int getPreset() const;
|
||||
|
||||
// Sets the current preset by ID.
|
||||
// All the band parameters will be overridden.
|
||||
// Change will not be applied until commit() is called.
|
||||
// preset The preset ID. Must be less than number of presets.
|
||||
// PRESET_CUSTOM is NOT a valid value here.
|
||||
void setPreset(int preset);
|
||||
|
||||
// Applies all parameter changes done to this point in time.
|
||||
// If the filter is disabled, the new parameters will take place when it is
|
||||
// enabled again. Does not introduce artifacts, unless immediate is set.
|
||||
// immediate Whether to apply change abruptly (ignored if filter is
|
||||
// disabled).
|
||||
void commit(bool immediate = false);
|
||||
|
||||
// Process a buffer of input data. The input and output should contain
|
||||
// frameCount * nChannels interlaced samples. Processing can be done
|
||||
// in-place, by passing the same buffer as both arguments.
|
||||
// pIn Input buffer.
|
||||
// pOut Output buffer.
|
||||
// frameCount Number of frames to produce on each call to process().
|
||||
void process(const audio_sample_t * pIn, audio_sample_t * pOut,
|
||||
int frameCount);
|
||||
|
||||
// Enables the filter, so it would start processing input. Does not
|
||||
// introduce artifacts, unless immediate is set.
|
||||
// immediate Whether to apply change abruptly.
|
||||
void enable(bool immediate = false);
|
||||
|
||||
// Disabled (bypasses) the filter. Does not introduce artifacts, unless
|
||||
// immediate is set.
|
||||
// immediate Whether to apply change abruptly.
|
||||
void disable(bool immediate = false);
|
||||
|
||||
// Returns the band with the maximum influence on a given frequency.
|
||||
// Result is unaffected by whether EQ is enabled or not, or by whether
|
||||
// changes have been committed or not.
|
||||
// targetFreq The target frequency, in millihertz.
|
||||
int getMostRelevantBand(uint32_t targetFreq) const;
|
||||
|
||||
private:
|
||||
// Bottom frequency, in mHz.
|
||||
static const int kMinFreq = 20000;
|
||||
// Sample rate, in Hz.
|
||||
int mSampleRate;
|
||||
// Number of peaking filters. Total number of bands is +2.
|
||||
int mNumPeaking;
|
||||
// Preset configurations.
|
||||
const PresetConfig * mpPresets;
|
||||
// Number of elements in mpPresets;
|
||||
int mNumPresets;
|
||||
// Current preset.
|
||||
int mCurPreset;
|
||||
|
||||
// Memory space to free when instance is deleted, or NULL if no memory is
|
||||
// owned.
|
||||
void * mpMem;
|
||||
// The low-shelving filter.
|
||||
AudioShelvingFilter * mpLowShelf;
|
||||
// The high-shelving filter.
|
||||
AudioShelvingFilter * mpHighShelf;
|
||||
// An array of size mNumPeaking of peaking filters.
|
||||
AudioPeakingFilter * mpPeakingFilters;
|
||||
|
||||
// Constructor. Resets the filter (see reset()). Must call init() doing
|
||||
// anything else.
|
||||
// pMem Memory buffer for bands.
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
// ownMem Whether pMem is owned by me.
|
||||
// presets The presets configuration. May be NULL, but in that case the
|
||||
// client is required not to call preset-related functions.
|
||||
// This array is owned by the client and is not copied. It
|
||||
// must be kept valid by the client as long as the instance is
|
||||
// alive.
|
||||
// nPresets Number of elements in the presets array.
|
||||
AudioEqualizer(void * pMem, int nBands, int nChannels, int sampleRate,
|
||||
bool ownMem, const PresetConfig * presets, int nPresets);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUDIOEQUALIZER_H_
|
184
media/libeffects/AudioFormatAdapter.h
Normal file
184
media/libeffects/AudioFormatAdapter.h
Normal file
@ -0,0 +1,184 @@
|
||||
/* /android/src/frameworks/base/media/libeffects/AudioFormatAdapter.h
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef AUDIOFORMATADAPTER_H_
|
||||
#define AUDIOFORMATADAPTER_H_
|
||||
|
||||
#include <media/EffectApi.h>
|
||||
|
||||
|
||||
#define min(x,y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
namespace android {
|
||||
|
||||
// An adapter for an audio processor working on audio_sample_t samples with a
|
||||
// buffer override behavior to arbitrary sample formats and buffer behaviors.
|
||||
// The adapter may work on any processing class which has a processing function
|
||||
// with the following signature:
|
||||
// void process(const audio_sample_t * pIn,
|
||||
// audio_sample_t * pOut,
|
||||
// int frameCount);
|
||||
// It is assumed that the underlying processor works in S7.24 format and an
|
||||
// overwrite behavior.
|
||||
//
|
||||
// Usage is simple: just work with the processor normally, but instead of
|
||||
// calling its process() function directly, work with the process() function of
|
||||
// the adapter.
|
||||
// The adapter supports re-configuration to a different format on the fly.
|
||||
//
|
||||
// T The processor class.
|
||||
// bufSize The maximum number of samples (single channel) to process on a
|
||||
// single call to the underlying processor. Setting this to a small
|
||||
// number will save a little memory, but will cost function call
|
||||
// overhead, resulting from multiple calls to the underlying process()
|
||||
// per a single call to this class's process().
|
||||
template<class T, size_t bufSize>
|
||||
class AudioFormatAdapter {
|
||||
public:
|
||||
// Configure the adapter.
|
||||
// processor The underlying audio processor.
|
||||
// nChannels Number of input and output channels. The adapter does not do
|
||||
// channel conversion - this parameter must be in sync with the
|
||||
// actual processor.
|
||||
// pcmFormat The desired input/output sample format.
|
||||
// behavior The desired behavior (overwrite or accumulate).
|
||||
void configure(T & processor, int nChannels, uint8_t pcmFormat,
|
||||
uint32_t behavior) {
|
||||
mpProcessor = &processor;
|
||||
mNumChannels = nChannels;
|
||||
mPcmFormat = pcmFormat;
|
||||
mBehavior = behavior;
|
||||
mMaxSamplesPerCall = bufSize / nChannels;
|
||||
}
|
||||
|
||||
// Process a block of samples.
|
||||
// pIn A buffer of samples with the format specified on
|
||||
// configure().
|
||||
// pOut A buffer of samples with the format specified on
|
||||
// configure(). May be the same as pIn.
|
||||
// numSamples The number of multi-channel samples to process.
|
||||
void process(const void * pIn, void * pOut, uint32_t numSamples) {
|
||||
while (numSamples > 0) {
|
||||
uint32_t numSamplesIter = min(numSamples, mMaxSamplesPerCall);
|
||||
uint32_t nSamplesChannels = numSamplesIter * mNumChannels;
|
||||
if (mPcmFormat == PCM_FORMAT_S7_24) {
|
||||
if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
|
||||
mpProcessor->process(
|
||||
reinterpret_cast<const audio_sample_t *> (pIn),
|
||||
reinterpret_cast<audio_sample_t *> (pOut),
|
||||
numSamplesIter);
|
||||
} else if (mBehavior == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
|
||||
mpProcessor->process(
|
||||
reinterpret_cast<const audio_sample_t *> (pIn),
|
||||
mBuffer, numSamplesIter);
|
||||
MixOutput(pOut, numSamplesIter);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
pIn = reinterpret_cast<const audio_sample_t *> (pIn)
|
||||
+ nSamplesChannels;
|
||||
pOut = reinterpret_cast<audio_sample_t *> (pOut)
|
||||
+ nSamplesChannels;
|
||||
} else {
|
||||
ConvertInput(pIn, nSamplesChannels);
|
||||
mpProcessor->process(mBuffer, mBuffer, numSamplesIter);
|
||||
ConvertOutput(pOut, nSamplesChannels);
|
||||
}
|
||||
numSamples -= numSamplesIter;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// The underlying processor.
|
||||
T * mpProcessor;
|
||||
// The number of input/output channels.
|
||||
int mNumChannels;
|
||||
// The desired PCM format.
|
||||
uint8_t mPcmFormat;
|
||||
// The desired buffer behavior.
|
||||
uint32_t mBehavior;
|
||||
// An intermediate buffer for processing.
|
||||
audio_sample_t mBuffer[bufSize];
|
||||
// The buffer size, divided by the number of channels - represents the
|
||||
// maximum number of multi-channel samples that can be stored in the
|
||||
// intermediate buffer.
|
||||
size_t mMaxSamplesPerCall;
|
||||
|
||||
// Converts a buffer of input samples to audio_sample_t format.
|
||||
// Output is written to the intermediate buffer.
|
||||
// pIn The input buffer with the format designated in configure().
|
||||
// When function exist will point to the next unread input
|
||||
// sample.
|
||||
// numSamples The number of single-channel samples to process.
|
||||
void ConvertInput(const void *& pIn, uint32_t numSamples) {
|
||||
if (mPcmFormat == PCM_FORMAT_S15) {
|
||||
const int16_t * pIn16 = reinterpret_cast<const int16_t *>(pIn);
|
||||
audio_sample_t * pOut = mBuffer;
|
||||
while (numSamples-- > 0) {
|
||||
*(pOut++) = s15_to_audio_sample_t(*(pIn16++));
|
||||
}
|
||||
pIn = pIn16;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Converts audio_sample_t samples from the intermediate buffer to the
|
||||
// output buffer, converting to the desired format and buffer behavior.
|
||||
// pOut The buffer to write the output to.
|
||||
// When function exist will point to the next output sample.
|
||||
// numSamples The number of single-channel samples to process.
|
||||
void ConvertOutput(void *& pOut, uint32_t numSamples) {
|
||||
if (mPcmFormat == PCM_FORMAT_S15) {
|
||||
const audio_sample_t * pIn = mBuffer;
|
||||
int16_t * pOut16 = reinterpret_cast<int16_t *>(pOut);
|
||||
if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
|
||||
while (numSamples-- > 0) {
|
||||
*(pOut16++) = audio_sample_t_to_s15_clip(*(pIn++));
|
||||
}
|
||||
} else if (mBehavior == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
|
||||
while (numSamples-- > 0) {
|
||||
*(pOut16++) += audio_sample_t_to_s15_clip(*(pIn++));
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
pOut = pOut16;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate data from the intermediate buffer to the output. Output is
|
||||
// assumed to be of audio_sample_t type.
|
||||
// pOut The buffer to mix the output to.
|
||||
// When function exist will point to the next output sample.
|
||||
// numSamples The number of single-channel samples to process.
|
||||
void MixOutput(void *& pOut, uint32_t numSamples) {
|
||||
const audio_sample_t * pIn = mBuffer;
|
||||
audio_sample_t * pOut24 = reinterpret_cast<audio_sample_t *>(pOut);
|
||||
numSamples *= mNumChannels;
|
||||
while (numSamples-- > 0) {
|
||||
*(pOut24++) += *(pIn++);
|
||||
}
|
||||
pOut = pOut24;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUDIOFORMATADAPTER_H_
|
225
media/libeffects/AudioHighShelfFilterCoef.inl
Normal file
225
media/libeffects/AudioHighShelfFilterCoef.inl
Normal file
@ -0,0 +1,225 @@
|
||||
13679,
|
||||
21575,
|
||||
8921,
|
||||
32315056,
|
||||
-15582015,
|
||||
26172,
|
||||
37678,
|
||||
14797,
|
||||
31891096,
|
||||
-15192527,
|
||||
51020,
|
||||
64449,
|
||||
23945,
|
||||
31322988,
|
||||
-14685186,
|
||||
101817,
|
||||
106144,
|
||||
37744,
|
||||
30562882,
|
||||
-14031372,
|
||||
208996,
|
||||
162163,
|
||||
58536,
|
||||
29548538,
|
||||
-13201017,
|
||||
442996,
|
||||
207459,
|
||||
93300,
|
||||
28200792,
|
||||
-12167331,
|
||||
971423,
|
||||
128786,
|
||||
169690,
|
||||
26422744,
|
||||
-10915428,
|
||||
2200461,
|
||||
-465686,
|
||||
394986,
|
||||
24103317,
|
||||
-9455862,
|
||||
5119991,
|
||||
-2777199,
|
||||
1147245,
|
||||
21129473,
|
||||
-7842294,
|
||||
12120379,
|
||||
-10198160,
|
||||
3631544,
|
||||
17411837,
|
||||
-6188384,
|
||||
28834234,
|
||||
-31647135,
|
||||
11337795,
|
||||
12924960,
|
||||
-4672638,
|
||||
68037766,
|
||||
-88974388,
|
||||
33477255,
|
||||
7752680,
|
||||
-3516098,
|
||||
157369944,
|
||||
-232063160,
|
||||
92282129,
|
||||
2113926,
|
||||
-2925624,
|
||||
353720112,
|
||||
-567427144,
|
||||
237164112,
|
||||
-3659993,
|
||||
-3019871,
|
||||
769091151,
|
||||
-1309871949,
|
||||
570539430,
|
||||
-9202114,
|
||||
-3779302,
|
||||
66791,
|
||||
121706,
|
||||
55888,
|
||||
30571245,
|
||||
-14038415,
|
||||
120426,
|
||||
212178,
|
||||
94820,
|
||||
29559679,
|
||||
-13209886,
|
||||
217130,
|
||||
365165,
|
||||
157610,
|
||||
28215554,
|
||||
-12178243,
|
||||
391489,
|
||||
617016,
|
||||
255010,
|
||||
26442131,
|
||||
-10928431,
|
||||
705862,
|
||||
1015147,
|
||||
398457,
|
||||
24128430,
|
||||
-9470680,
|
||||
1272682,
|
||||
1605251,
|
||||
596102,
|
||||
21161334,
|
||||
-7858153,
|
||||
2294668,
|
||||
2386833,
|
||||
848523,
|
||||
17451072,
|
||||
-6203880,
|
||||
4137327,
|
||||
3198789,
|
||||
1155536,
|
||||
12971362,
|
||||
-4685798,
|
||||
7459675,
|
||||
3470266,
|
||||
1567219,
|
||||
7804818,
|
||||
-3524761,
|
||||
13449926,
|
||||
1738911,
|
||||
2347406,
|
||||
2169089,
|
||||
-2928116,
|
||||
24250455,
|
||||
-5211241,
|
||||
4358971,
|
||||
-3605298,
|
||||
-3015671,
|
||||
43724001,
|
||||
-23849570,
|
||||
9823315,
|
||||
-9151253,
|
||||
-3769277,
|
||||
78835150,
|
||||
-66542375,
|
||||
23686373,
|
||||
-14161143,
|
||||
-5040790,
|
||||
142141173,
|
||||
-156324261,
|
||||
56024234,
|
||||
-18451275,
|
||||
-6612656,
|
||||
256283057,
|
||||
-335606326,
|
||||
126341244,
|
||||
-21970004,
|
||||
-8270755,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
||||
16777216,
|
||||
33554432,
|
||||
16777216,
|
||||
-33554432,
|
||||
-16777216,
|
375
media/libeffects/AudioLowShelfFilterCoef.inl
Normal file
375
media/libeffects/AudioLowShelfFilterCoef.inl
Normal file
@ -0,0 +1,375 @@
|
||||
16212506,
|
||||
-32420574,
|
||||
16208068,
|
||||
32401411,
|
||||
-15662521,
|
||||
16356129,
|
||||
-32706246,
|
||||
16350118,
|
||||
32695525,
|
||||
-15939752,
|
||||
16464399,
|
||||
-32920670,
|
||||
16456274,
|
||||
32914686,
|
||||
-16149441,
|
||||
16546128,
|
||||
-33081289,
|
||||
16535165,
|
||||
33077955,
|
||||
-16307411,
|
||||
16608101,
|
||||
-33201422,
|
||||
16593328,
|
||||
33199569,
|
||||
-16426067,
|
||||
16655539,
|
||||
-33291174,
|
||||
16635647,
|
||||
33290147,
|
||||
-16514997,
|
||||
16692478,
|
||||
-33358171,
|
||||
16665715,
|
||||
33357608,
|
||||
-16581540,
|
||||
16722089,
|
||||
-33408149,
|
||||
16686099,
|
||||
33407850,
|
||||
-16631271,
|
||||
16746930,
|
||||
-33445409,
|
||||
16698549,
|
||||
33445267,
|
||||
-16668405,
|
||||
16769156,
|
||||
-33473168,
|
||||
16704138,
|
||||
33473133,
|
||||
-16696114,
|
||||
16790706,
|
||||
-33493827,
|
||||
16703348,
|
||||
33493886,
|
||||
-16716779,
|
||||
16813466,
|
||||
-33509166,
|
||||
16696111,
|
||||
33509342,
|
||||
-16732186,
|
||||
16839437,
|
||||
-33520498,
|
||||
16681802,
|
||||
33520852,
|
||||
-16743669,
|
||||
16870911,
|
||||
-33528765,
|
||||
16659191,
|
||||
33529424,
|
||||
-16752226,
|
||||
16910681,
|
||||
-33534607,
|
||||
16626337,
|
||||
33535807,
|
||||
-16758602,
|
||||
15667401,
|
||||
-31326224,
|
||||
15658825,
|
||||
31252161,
|
||||
-14623074,
|
||||
15945865,
|
||||
-31880007,
|
||||
15934146,
|
||||
31838205,
|
||||
-15144597,
|
||||
16157521,
|
||||
-32299091,
|
||||
16141578,
|
||||
32275604,
|
||||
-15545369,
|
||||
16318267,
|
||||
-32614903,
|
||||
16296651,
|
||||
32601755,
|
||||
-15850850,
|
||||
16440710,
|
||||
-32852157,
|
||||
16411473,
|
||||
32844820,
|
||||
-16082303,
|
||||
16534751,
|
||||
-33029985,
|
||||
16495281,
|
||||
33025910,
|
||||
-16256891,
|
||||
16608171,
|
||||
-33163043,
|
||||
16554957,
|
||||
33160803,
|
||||
-16388152,
|
||||
16667145,
|
||||
-33262468,
|
||||
16595477,
|
||||
33261275,
|
||||
-16486599,
|
||||
16716699,
|
||||
-33336671,
|
||||
16620252,
|
||||
33336105,
|
||||
-16560301,
|
||||
16761100,
|
||||
-33391976,
|
||||
16631379,
|
||||
33391836,
|
||||
-16615404,
|
||||
16804207,
|
||||
-33433103,
|
||||
16629806,
|
||||
33433341,
|
||||
-16656560,
|
||||
16849794,
|
||||
-33463551,
|
||||
16615399,
|
||||
33464251,
|
||||
-16687277,
|
||||
16901887,
|
||||
-33485857,
|
||||
16586933,
|
||||
33487271,
|
||||
-16710189,
|
||||
16965125,
|
||||
-33501781,
|
||||
16542000,
|
||||
33504415,
|
||||
-16727274,
|
||||
17045198,
|
||||
-33512384,
|
||||
16476824,
|
||||
33517183,
|
||||
-16740008,
|
||||
14635201,
|
||||
-29254376,
|
||||
14619184,
|
||||
28977711,
|
||||
-12753834,
|
||||
15157556,
|
||||
-30292825,
|
||||
15135285,
|
||||
30133938,
|
||||
-13674513,
|
||||
15561511,
|
||||
-31092298,
|
||||
15530817,
|
||||
31001860,
|
||||
-14405551,
|
||||
15872211,
|
||||
-31702342,
|
||||
15830187,
|
||||
31651218,
|
||||
-14976306,
|
||||
16111094,
|
||||
-32164834,
|
||||
16053843,
|
||||
32136101,
|
||||
-15416453,
|
||||
16295848,
|
||||
-32513802,
|
||||
16218140,
|
||||
32497757,
|
||||
-15752817,
|
||||
16440852,
|
||||
-32776179,
|
||||
16335665,
|
||||
32767326,
|
||||
-16008155,
|
||||
16557804,
|
||||
-32972907,
|
||||
16415715,
|
||||
32968179,
|
||||
-16201031,
|
||||
16656403,
|
||||
-33120052,
|
||||
16464758,
|
||||
33117802,
|
||||
-16346195,
|
||||
16745001,
|
||||
-33229805,
|
||||
16486810,
|
||||
33229247,
|
||||
-16455153,
|
||||
16831240,
|
||||
-33311306,
|
||||
16483692,
|
||||
33312252,
|
||||
-16536771,
|
||||
16922682,
|
||||
-33371278,
|
||||
16455145,
|
||||
33374070,
|
||||
-16597819,
|
||||
17027472,
|
||||
-33414465,
|
||||
16398818,
|
||||
33420110,
|
||||
-16643430,
|
||||
17155108,
|
||||
-33443875,
|
||||
16310110,
|
||||
33454398,
|
||||
-16677479,
|
||||
17317384,
|
||||
-33460760,
|
||||
16181887,
|
||||
33479933,
|
||||
-16702882,
|
||||
12792703,
|
||||
-25557388,
|
||||
12764716,
|
||||
24590507,
|
||||
-9747085,
|
||||
13706465,
|
||||
-27372621,
|
||||
13666215,
|
||||
26798296,
|
||||
-11169790,
|
||||
14439425,
|
||||
-28821830,
|
||||
14382518,
|
||||
28486469,
|
||||
-12380088,
|
||||
15018453,
|
||||
-29957273,
|
||||
14939030,
|
||||
29764018,
|
||||
-13373522,
|
||||
15472460,
|
||||
-30834757,
|
||||
15362688,
|
||||
30724568,
|
||||
-14168120,
|
||||
15828725,
|
||||
-31506123,
|
||||
15678118,
|
||||
31443928,
|
||||
-14791822,
|
||||
16111406,
|
||||
-32015988,
|
||||
15905901,
|
||||
31981391,
|
||||
-15274688,
|
||||
16341329,
|
||||
-32400984,
|
||||
16062061,
|
||||
32382398,
|
||||
-15644761,
|
||||
16536484,
|
||||
-32690238,
|
||||
16158133,
|
||||
32681354,
|
||||
-15926286,
|
||||
16712853,
|
||||
-32906337,
|
||||
16201432,
|
||||
32904128,
|
||||
-16139278,
|
||||
16885430,
|
||||
-33066336,
|
||||
16195306,
|
||||
33070090,
|
||||
-16299767,
|
||||
17069377,
|
||||
-33182599,
|
||||
16139282,
|
||||
33193711,
|
||||
-16420332,
|
||||
17281371,
|
||||
-33263294,
|
||||
16029039,
|
||||
33285785,
|
||||
-16510702,
|
||||
17541271,
|
||||
-33312390,
|
||||
15856243,
|
||||
33354359,
|
||||
-16578329,
|
||||
17874330,
|
||||
-33328902,
|
||||
15608287,
|
||||
33405430,
|
||||
-16628873,
|
||||
9881279,
|
||||
-19719268,
|
||||
9838084,
|
||||
16734303,
|
||||
-5927111,
|
||||
11264857,
|
||||
-22463447,
|
||||
11198784,
|
||||
20577584,
|
||||
-7572288,
|
||||
12460736,
|
||||
-24823046,
|
||||
12362697,
|
||||
23667359,
|
||||
-9201903,
|
||||
13459805,
|
||||
-26776851,
|
||||
13317799,
|
||||
26085683,
|
||||
-10691555,
|
||||
14276287,
|
||||
-28349256,
|
||||
14074406,
|
||||
27943899,
|
||||
-11978834,
|
||||
14936943,
|
||||
-29588248,
|
||||
14654011,
|
||||
29354533,
|
||||
-13047453,
|
||||
15473300,
|
||||
-30549299,
|
||||
15081036,
|
||||
30417203,
|
||||
-13909216,
|
||||
15917271,
|
||||
-31285788,
|
||||
15377817,
|
||||
31213972,
|
||||
-14589687,
|
||||
16299384,
|
||||
-31844320,
|
||||
15562006,
|
||||
31809683,
|
||||
-15118811,
|
||||
16648774,
|
||||
-32262999,
|
||||
15645414,
|
||||
32254329,
|
||||
-15525641,
|
||||
16994277,
|
||||
-32571090,
|
||||
15633607,
|
||||
32585895,
|
||||
-15835862,
|
||||
17366374,
|
||||
-32789019,
|
||||
15525801,
|
||||
32833003,
|
||||
-16070975,
|
||||
17799955,
|
||||
-32927834,
|
||||
15314895,
|
||||
33017107,
|
||||
-16248361,
|
||||
18338206,
|
||||
-32987318,
|
||||
14987686,
|
||||
33154246,
|
||||
-16381747,
|
||||
19038270,
|
||||
-32951545,
|
||||
14525592,
|
||||
33256392,
|
||||
-16481800,
|
121
media/libeffects/AudioPeakingFilter.cpp
Normal file
121
media/libeffects/AudioPeakingFilter.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/* //device/include/server/AudioFlinger/AudioPeakingFilter.cpp
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
|
||||
#include "AudioPeakingFilter.h"
|
||||
#include "AudioCommon.h"
|
||||
#include "EffectsMath.h"
|
||||
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
|
||||
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
|
||||
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
|
||||
|
||||
namespace android {
|
||||
// Format of the coefficient table:
|
||||
// kCoefTable[freq][gain][bw][coef]
|
||||
// freq - peak frequency, in octaves below Nyquist,from -9 to -1.
|
||||
// gain - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel.
|
||||
// bw - bandwidth, starting at 1 cent, jumps of 1024, to 3073 cents.
|
||||
// coef - 0: b0
|
||||
// 1: b1
|
||||
// 2: b2
|
||||
// 3: -a1
|
||||
// 4: -a2
|
||||
static const size_t kInDims[3] = {9, 15, 4};
|
||||
static const audio_coef_t kCoefTable[9*15*4*5] = {
|
||||
#include "AudioPeakingFilterCoef.inl"
|
||||
};
|
||||
|
||||
AudioCoefInterpolator AudioPeakingFilter::mCoefInterp(3, kInDims, 5, (const audio_coef_t*) kCoefTable);
|
||||
|
||||
AudioPeakingFilter::AudioPeakingFilter(int nChannels, int sampleRate)
|
||||
: mBiquad(nChannels, sampleRate) {
|
||||
configure(nChannels, sampleRate);
|
||||
reset();
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::configure(int nChannels, int sampleRate) {
|
||||
mNiquistFreq = sampleRate * 500;
|
||||
mFrequencyFactor = ((1ull) << 42) / mNiquistFreq;
|
||||
mBiquad.configure(nChannels, sampleRate);
|
||||
setFrequency(mNominalFrequency);
|
||||
commit(true);
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::reset() {
|
||||
setGain(0);
|
||||
setFrequency(0);
|
||||
setBandwidth(2400);
|
||||
commit(true);
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::setFrequency(uint32_t millihertz) {
|
||||
mNominalFrequency = millihertz;
|
||||
if (UNLIKELY(millihertz > mNiquistFreq / 2)) {
|
||||
millihertz = mNiquistFreq / 2;
|
||||
}
|
||||
uint32_t normFreq = static_cast<uint32_t>(
|
||||
(static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10);
|
||||
if (LIKELY(normFreq > (1 << 23))) {
|
||||
mFrequency = (Effects_log2(normFreq) - ((32-9) << 15)) << (FREQ_PRECISION_BITS - 15);
|
||||
} else {
|
||||
mFrequency = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::setGain(int32_t millibel) {
|
||||
mGain = millibel + 9600;
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::setBandwidth(uint32_t cents) {
|
||||
mBandwidth = cents - 1;
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::commit(bool immediate) {
|
||||
audio_coef_t coefs[5];
|
||||
int intCoord[3] = {
|
||||
mFrequency >> FREQ_PRECISION_BITS,
|
||||
mGain >> GAIN_PRECISION_BITS,
|
||||
mBandwidth >> BANDWIDTH_PRECISION_BITS
|
||||
};
|
||||
uint32_t fracCoord[3] = {
|
||||
mFrequency << (32 - FREQ_PRECISION_BITS),
|
||||
static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS),
|
||||
mBandwidth << (32 - BANDWIDTH_PRECISION_BITS)
|
||||
};
|
||||
mCoefInterp.getCoef(intCoord, fracCoord, coefs);
|
||||
mBiquad.setCoefs(coefs, immediate);
|
||||
}
|
||||
|
||||
void AudioPeakingFilter::getBandRange(uint32_t & low, uint32_t & high) const {
|
||||
// Half bandwidth, in octaves, 15-bit precision
|
||||
int32_t halfBW = (((mBandwidth + 1) / 2) << 15) / 1200;
|
||||
|
||||
low = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(-halfBW + (16 << 15))) >> 16);
|
||||
if (UNLIKELY(halfBW >= (16 << 15))) {
|
||||
high = mNiquistFreq;
|
||||
} else {
|
||||
high = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(halfBW + (16 << 15))) >> 16);
|
||||
if (UNLIKELY(high > mNiquistFreq)) {
|
||||
high = mNiquistFreq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
151
media/libeffects/AudioPeakingFilter.h
Normal file
151
media/libeffects/AudioPeakingFilter.h
Normal file
@ -0,0 +1,151 @@
|
||||
/* //device/include/server/AudioFlinger/AudioPeakingFilter.h
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIO_PEAKING_FILTER_H
|
||||
#define ANDROID_AUDIO_PEAKING_FILTER_H
|
||||
|
||||
#include "AudioBiquadFilter.h"
|
||||
#include "AudioCoefInterpolator.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// A peaking audio filter, with unity skirt gain, and controllable peak
|
||||
// frequency, gain and bandwidth.
|
||||
// This filter is able to suppress introduce discontinuities and other artifacts
|
||||
// in the output, even when changing parameters abruptly.
|
||||
// Parameters can be set to any value - this class will make sure to clip them
|
||||
// when they are out of supported range.
|
||||
//
|
||||
// Implementation notes:
|
||||
// This class uses an underlying biquad filter whose parameters are determined
|
||||
// using a linear interpolation from a coefficient table, using a
|
||||
// AudioCoefInterpolator.
|
||||
// All is left for this class to do is mapping between high-level parameters to
|
||||
// fractional indices into the coefficient table.
|
||||
class AudioPeakingFilter {
|
||||
public:
|
||||
// Constructor. Resets the filter (see reset()).
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
AudioPeakingFilter(int nChannels, int sampleRate);
|
||||
|
||||
// Reconfiguration of the filter. Changes input/output format, but does not
|
||||
// alter current parameter values. Clears delay lines.
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
void configure(int nChannels, int sampleRate);
|
||||
|
||||
// Resets the filter parameters to the following values:
|
||||
// frequency: 0
|
||||
// gain: 0
|
||||
// bandwidth: 1200 cents.
|
||||
// It also disables the filter. Does not clear the delay lines.
|
||||
void reset();
|
||||
|
||||
// Clears delay lines. Does not alter parameter values.
|
||||
void clear() { mBiquad.clear(); }
|
||||
|
||||
// Sets gain value. Actual change will only take place upon commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// millibel Gain value in millibel (1/100 of decibel).
|
||||
void setGain(int32_t millibel);
|
||||
|
||||
// Gets the gain, in millibel, as set.
|
||||
int32_t getGain() const { return mGain - 9600; }
|
||||
|
||||
// Sets bandwidth value. Actual change will only take place upon commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// cents Bandwidth value in cents (1/1200 octave).
|
||||
void setBandwidth(uint32_t cents);
|
||||
|
||||
// Gets the gain, in cents, as set.
|
||||
uint32_t getBandwidth() const { return mBandwidth + 1; }
|
||||
|
||||
// Sets frequency value. Actual change will only take place upon commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// millihertz Frequency value in mHz.
|
||||
void setFrequency(uint32_t millihertz);
|
||||
|
||||
// Gets the frequency, in mHz, as set.
|
||||
uint32_t getFrequency() const { return mNominalFrequency; }
|
||||
|
||||
// Gets gain[dB]/2 points.
|
||||
// Results in mHz, and are computed based on the nominal values set, not on
|
||||
// possibly rounded or truncated actual values.
|
||||
void getBandRange(uint32_t & low, uint32_t & high) const;
|
||||
|
||||
// Applies all parameter changes done to this point in time.
|
||||
// If the filter is disabled, the new parameters will take place when it is
|
||||
// enabled again. Does not introduce artifacts, unless immediate is set.
|
||||
// immediate Whether to apply change abruptly (ignored if filter is
|
||||
// disabled).
|
||||
void commit(bool immediate = false);
|
||||
|
||||
// Process a buffer of input data. The input and output should contain
|
||||
// frameCount * nChannels interlaced samples. Processing can be done
|
||||
// in-place, by passing the same buffer as both arguments.
|
||||
// in Input buffer.
|
||||
// out Output buffer.
|
||||
// frameCount Number of frames to produce.
|
||||
void process(const audio_sample_t in[], audio_sample_t out[],
|
||||
int frameCount) { mBiquad.process(in, out, frameCount); }
|
||||
|
||||
// Enables the filter, so it would start processing input. Does not
|
||||
// introduce artifacts, unless immediate is set.
|
||||
// immediate Whether to apply change abruptly.
|
||||
void enable(bool immediate = false) { mBiquad.enable(immediate); }
|
||||
|
||||
// Disabled (bypasses) the filter. Does not introduce artifacts, unless
|
||||
// immediate is set.
|
||||
// immediate Whether to apply change abruptly.
|
||||
void disable(bool immediate = false) { mBiquad.disable(immediate); }
|
||||
|
||||
private:
|
||||
// Precision for the mFrequency member.
|
||||
static const int FREQ_PRECISION_BITS = 26;
|
||||
// Precision for the mGain member.
|
||||
static const int GAIN_PRECISION_BITS = 10;
|
||||
// Precision for the mBandwidth member.
|
||||
static const int BANDWIDTH_PRECISION_BITS = 10;
|
||||
|
||||
// Nyquist, in mHz.
|
||||
uint32_t mNiquistFreq;
|
||||
// Fractional index into the gain dimension of the coef table in
|
||||
// GAIN_PRECISION_BITS precision.
|
||||
int32_t mGain;
|
||||
// Fractional index into the bandwidth dimension of the coef table in
|
||||
// BANDWIDTH_PRECISION_BITS precision.
|
||||
uint32_t mBandwidth;
|
||||
// Fractional index into the frequency dimension of the coef table in
|
||||
// FREQ_PRECISION_BITS precision.
|
||||
uint32_t mFrequency;
|
||||
// Nominal value of frequency, as set.
|
||||
uint32_t mNominalFrequency;
|
||||
// 1/Nyquist[mHz], in 42-bit precision (very small).
|
||||
// Used for scaling the frequency.
|
||||
uint32_t mFrequencyFactor;
|
||||
|
||||
// A biquad filter, used for the actual processing.
|
||||
AudioBiquadFilter mBiquad;
|
||||
// A coefficient interpolator, used for mapping the high level parameters to
|
||||
// the low-level biquad coefficients.
|
||||
static AudioCoefInterpolator mCoefInterp;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ANDROID_AUDIO_PEAKING_FILTER_H
|
2700
media/libeffects/AudioPeakingFilterCoef.inl
Normal file
2700
media/libeffects/AudioPeakingFilterCoef.inl
Normal file
File diff suppressed because it is too large
Load Diff
109
media/libeffects/AudioShelvingFilter.cpp
Normal file
109
media/libeffects/AudioShelvingFilter.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/* /android/src/frameworks/base/libs/audioflinger/AudioShelvingFilter.cpp
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
|
||||
#include "AudioShelvingFilter.h"
|
||||
#include "AudioCommon.h"
|
||||
#include "EffectsMath.h"
|
||||
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
|
||||
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
|
||||
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
|
||||
|
||||
namespace android {
|
||||
// Format of the coefficient tables:
|
||||
// kCoefTable[freq][gain][coef]
|
||||
// freq - cutoff frequency, in octaves below Nyquist,from -10 to -6 in low
|
||||
// shelf, -2 to 0 in high shelf.
|
||||
// gain - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel.
|
||||
// coef - 0: b0
|
||||
// 1: b1
|
||||
// 2: b2
|
||||
// 3: -a1
|
||||
// 4: -a2
|
||||
static const size_t kHiInDims[2] = {3, 15};
|
||||
static const audio_coef_t kHiCoefTable[3*15*5] = {
|
||||
#include "AudioHighShelfFilterCoef.inl"
|
||||
};
|
||||
static const size_t kLoInDims[2] = {5, 15};
|
||||
static const audio_coef_t kLoCoefTable[5*15*5] = {
|
||||
#include "AudioLowShelfFilterCoef.inl"
|
||||
};
|
||||
|
||||
AudioCoefInterpolator AudioShelvingFilter::mHiCoefInterp(2, kHiInDims, 5, (const audio_coef_t*) kHiCoefTable);
|
||||
AudioCoefInterpolator AudioShelvingFilter::mLoCoefInterp(2, kLoInDims, 5, (const audio_coef_t*) kLoCoefTable);
|
||||
|
||||
AudioShelvingFilter::AudioShelvingFilter(ShelfType type, int nChannels,
|
||||
int sampleRate)
|
||||
: mBiquad(nChannels, sampleRate)
|
||||
, mType(type) {
|
||||
configure(nChannels, sampleRate);
|
||||
}
|
||||
|
||||
void AudioShelvingFilter::configure(int nChannels, int sampleRate) {
|
||||
mNiquistFreq = sampleRate * 500;
|
||||
mFrequencyFactor = ((1ull) << 42) / mNiquistFreq;
|
||||
mBiquad.configure(nChannels, sampleRate);
|
||||
setFrequency(mNominalFrequency);
|
||||
commit(true);
|
||||
}
|
||||
|
||||
void AudioShelvingFilter::reset() {
|
||||
setGain(0);
|
||||
setFrequency(mType == kLowShelf ? 0 : mNiquistFreq);
|
||||
commit(true);
|
||||
}
|
||||
|
||||
void AudioShelvingFilter::setFrequency(uint32_t millihertz) {
|
||||
mNominalFrequency = millihertz;
|
||||
if (UNLIKELY(millihertz > mNiquistFreq / 2)) {
|
||||
millihertz = mNiquistFreq / 2;
|
||||
}
|
||||
uint32_t normFreq = static_cast<uint32_t>(
|
||||
(static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10);
|
||||
uint32_t log2minFreq = (mType == kLowShelf ? (32-10) : (32-2));
|
||||
if (LIKELY(normFreq > (1U << log2minFreq))) {
|
||||
mFrequency = (Effects_log2(normFreq) - (log2minFreq << 15)) << (FREQ_PRECISION_BITS - 15);
|
||||
} else {
|
||||
mFrequency = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioShelvingFilter::setGain(int32_t millibel) {
|
||||
mGain = millibel + 9600;
|
||||
}
|
||||
|
||||
void AudioShelvingFilter::commit(bool immediate) {
|
||||
audio_coef_t coefs[5];
|
||||
int intCoord[2] = {
|
||||
mFrequency >> FREQ_PRECISION_BITS,
|
||||
mGain >> GAIN_PRECISION_BITS
|
||||
};
|
||||
uint32_t fracCoord[2] = {
|
||||
mFrequency << (32 - FREQ_PRECISION_BITS),
|
||||
static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS)
|
||||
};
|
||||
if (mType == kHighShelf) {
|
||||
mHiCoefInterp.getCoef(intCoord, fracCoord, coefs);
|
||||
} else {
|
||||
mLoCoefInterp.getCoef(intCoord, fracCoord, coefs);
|
||||
}
|
||||
mBiquad.setCoefs(coefs, immediate);
|
||||
}
|
||||
|
||||
}
|
146
media/libeffects/AudioShelvingFilter.h
Normal file
146
media/libeffects/AudioShelvingFilter.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* /android/src/frameworks/base/libs/audioflinger/AudioShelvingFilter.h
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef AUDIO_SHELVING_FILTER_H
|
||||
#define AUDIO_SHELVING_FILTER_H
|
||||
|
||||
#include "AudioBiquadFilter.h"
|
||||
#include "AudioCoefInterpolator.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// A shelving audio filter, with unity skirt gain, and controllable cutoff
|
||||
// frequency and gain.
|
||||
// This filter is able to suppress introduce discontinuities and other artifacts
|
||||
// in the output, even when changing parameters abruptly.
|
||||
// Parameters can be set to any value - this class will make sure to clip them
|
||||
// when they are out of supported range.
|
||||
//
|
||||
// Implementation notes:
|
||||
// This class uses an underlying biquad filter whose parameters are determined
|
||||
// using a linear interpolation from a coefficient table, using a
|
||||
// AudioCoefInterpolator.
|
||||
// All is left for this class to do is mapping between high-level parameters to
|
||||
// fractional indices into the coefficient table.
|
||||
class AudioShelvingFilter {
|
||||
public:
|
||||
// Shelf type
|
||||
enum ShelfType {
|
||||
kLowShelf,
|
||||
kHighShelf
|
||||
};
|
||||
|
||||
// Constructor. Resets the filter (see reset()).
|
||||
// type Type of the filter (high shelf or low shelf).
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
AudioShelvingFilter(ShelfType type, int nChannels, int sampleRate);
|
||||
|
||||
// Reconfiguration of the filter. Changes input/output format, but does not
|
||||
// alter current parameter values. Clears delay lines.
|
||||
// nChannels Number of input/output channels (interlaced).
|
||||
// sampleRate The input/output sample rate, in Hz.
|
||||
void configure(int nChannels, int sampleRate);
|
||||
|
||||
// Resets the filter parameters to the following values:
|
||||
// frequency: 0
|
||||
// gain: 0
|
||||
// It also disables the filter. Does not clear the delay lines.
|
||||
void reset();
|
||||
|
||||
// Clears delay lines. Does not alter parameter values.
|
||||
void clear() { mBiquad.clear(); }
|
||||
|
||||
// Sets gain value. Actual change will only take place upon commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// millibel Gain value in millibel (1/100 of decibel).
|
||||
void setGain(int32_t millibel);
|
||||
|
||||
// Gets the gain, in millibel, as set.
|
||||
int32_t getGain() const { return mGain - 9600; }
|
||||
|
||||
// Sets cutoff frequency value. Actual change will only take place upon
|
||||
// commit().
|
||||
// This value will be remembered even if the filter is in disabled() state.
|
||||
// millihertz Frequency value in mHz.
|
||||
void setFrequency(uint32_t millihertz);
|
||||
|
||||
// Gets the frequency, in mHz, as set.
|
||||
uint32_t getFrequency() const { return mNominalFrequency; }
|
||||
|
||||
// Applies all parameter changes done to this point in time.
|
||||
// If the filter is disabled, the new parameters will take place when it is
|
||||
// enabled again. Does not introduce artifacts, unless immediate is set.
|
||||
// immediate Whether to apply change abruptly (ignored if filter is
|
||||
// disabled).
|
||||
void commit(bool immediate = false);
|
||||
|
||||
// Process a buffer of input data. The input and output should contain
|
||||
// frameCount * nChannels interlaced samples. Processing can be done
|
||||
// in-place, by passing the same buffer as both arguments.
|
||||
// in Input buffer.
|
||||
// out Output buffer.
|
||||
// frameCount Number of frames to produce.
|
||||
void process(const audio_sample_t in[], audio_sample_t out[],
|
||||
int frameCount) { mBiquad.process(in, out, frameCount); }
|
||||
|
||||
// Enables the filter, so it would start processing input. Does not
|
||||
// introduce artifacts, unless immediate is set.
|
||||
// immediate Whether to apply change abruptly.
|
||||
void enable(bool immediate = false) { mBiquad.enable(immediate); }
|
||||
|
||||
// Disabled (bypasses) the filter. Does not introduce artifacts, unless
|
||||
// immediate is set.
|
||||
// immediate Whether to apply change abruptly.
|
||||
void disable(bool immediate = false) { mBiquad.disable(immediate); }
|
||||
|
||||
private:
|
||||
// Precision for the mFrequency member.
|
||||
static const int FREQ_PRECISION_BITS = 26;
|
||||
// Precision for the mGain member.
|
||||
static const int GAIN_PRECISION_BITS = 10;
|
||||
|
||||
// Shelf type.
|
||||
ShelfType mType;
|
||||
// Nyquist, in mHz.
|
||||
uint32_t mNiquistFreq;
|
||||
// Fractional index into the gain dimension of the coef table in
|
||||
// GAIN_PRECISION_BITS precision.
|
||||
int32_t mGain;
|
||||
// Fractional index into the frequency dimension of the coef table in
|
||||
// FREQ_PRECISION_BITS precision.
|
||||
uint32_t mFrequency;
|
||||
// Nominal value of frequency, as set.
|
||||
uint32_t mNominalFrequency;
|
||||
// 1/Nyquist[mHz], in 42-bit precision (very small).
|
||||
// Used for scaling the frequency.
|
||||
uint32_t mFrequencyFactor;
|
||||
|
||||
// A biquad filter, used for the actual processing.
|
||||
AudioBiquadFilter mBiquad;
|
||||
// A coefficient interpolator, used for mapping the high level parameters to
|
||||
// the low-level biquad coefficients. This one is used for the high shelf.
|
||||
static AudioCoefInterpolator mHiCoefInterp;
|
||||
// A coefficient interpolator, used for mapping the high level parameters to
|
||||
// the low-level biquad coefficients. This one is used for the low shelf.
|
||||
static AudioCoefInterpolator mLoCoefInterp;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // AUDIO_SHELVING_FILTER_H
|
605
media/libeffects/EffectEqualizer.cpp
Normal file
605
media/libeffects/EffectEqualizer.cpp
Normal file
@ -0,0 +1,605 @@
|
||||
/*
|
||||
* 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 <cutils/log.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
#include "AudioEqualizer.h"
|
||||
#include "AudioBiquadFilter.h"
|
||||
#include "AudioFormatAdapter.h"
|
||||
#include <media/EffectEqualizerApi.h>
|
||||
|
||||
// effect_interface_t interface implementation for equalizer effect
|
||||
extern "C" const struct effect_interface_s gEqualizerInterface;
|
||||
|
||||
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_API_VERSION,
|
||||
(EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST),
|
||||
"Graphic Equalizer",
|
||||
"Google Inc.",
|
||||
};
|
||||
static int gEffectIndex;
|
||||
|
||||
/////////////////// 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<AudioEqualizer, kBufferSize> FormatAdapter;
|
||||
|
||||
struct EqualizerContext {
|
||||
const struct effect_interface_s *itfe;
|
||||
effect_config_t config;
|
||||
FormatAdapter adapter;
|
||||
AudioEqualizer * pEqualizer;
|
||||
};
|
||||
|
||||
|
||||
//--- local function prototypes
|
||||
|
||||
int Equalizer_init(EqualizerContext *pContext);
|
||||
int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig);
|
||||
int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue);
|
||||
int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue);
|
||||
|
||||
|
||||
//
|
||||
//--- Effect Library Interface Implementation
|
||||
//
|
||||
|
||||
extern "C" int EffectQueryNumberEffects(int *pNumEffects) {
|
||||
*pNumEffects = 1;
|
||||
gEffectIndex = 0;
|
||||
return 0;
|
||||
} /* end EffectQueryNumberEffects */
|
||||
|
||||
extern "C" int EffectQueryNext(effect_descriptor_t *pDescriptor) {
|
||||
if (pDescriptor == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (gEffectIndex++ > 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
memcpy(pDescriptor, &gEqualizerDescriptor, sizeof(effect_descriptor_t));
|
||||
return 0;
|
||||
} /* end EffectQueryNext */
|
||||
|
||||
extern "C" int EffectCreate(effect_uuid_t *uuid,
|
||||
effect_interface_t *pInterface) {
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
LOGV("EffectLibCreateEffect start");
|
||||
|
||||
if (pInterface == 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;
|
||||
|
||||
ret = Equalizer_init(pContext);
|
||||
if (ret < 0) {
|
||||
LOGW("EffectLibCreateEffect() init failed");
|
||||
delete pContext;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*pInterface = (effect_interface_t)pContext;
|
||||
|
||||
LOGV("EffectLibCreateEffect %p", pContext);
|
||||
|
||||
return 0;
|
||||
|
||||
} /* end EffectCreate */
|
||||
|
||||
extern "C" int EffectRelease(effect_interface_t interface) {
|
||||
EqualizerContext * pContext = (EqualizerContext *)interface;
|
||||
|
||||
LOGV("EffectLibReleaseEffect %p", interface);
|
||||
if (pContext == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pContext->pEqualizer->free();
|
||||
delete pContext;
|
||||
|
||||
return 0;
|
||||
} /* end EffectRelease */
|
||||
|
||||
|
||||
//
|
||||
//--- local functions
|
||||
//
|
||||
|
||||
#define CHECK_ARG(cond) { \
|
||||
if (!(cond)) { \
|
||||
LOGV("Invalid argument: "#cond); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Equalizer_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 Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig)
|
||||
{
|
||||
LOGV("Equalizer_configure 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 == CHANNEL_MONO) || (pConfig->inputCfg.channels == CHANNEL_STEREO));
|
||||
CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
|
||||
|| pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
|
||||
CHECK_ARG(pConfig->inputCfg.format == PCM_FORMAT_S7_24
|
||||
|| pConfig->inputCfg.format == PCM_FORMAT_S15);
|
||||
|
||||
int channelCount;
|
||||
if (pConfig->inputCfg.channels == CHANNEL_MONO) {
|
||||
channelCount = 1;
|
||||
} else {
|
||||
channelCount = 2;
|
||||
}
|
||||
CHECK_ARG(channelCount <= AudioBiquadFilter::MAX_CHANNELS);
|
||||
|
||||
pContext->pEqualizer->configure(channelCount,
|
||||
pConfig->inputCfg.samplingRate);
|
||||
|
||||
pContext->adapter.configure(*pContext->pEqualizer, channelCount,
|
||||
pConfig->inputCfg.format,
|
||||
pConfig->outputCfg.accessMode);
|
||||
|
||||
return 0;
|
||||
} // end Equalizer_configure
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
LOGV("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 = CHANNEL_STEREO;
|
||||
pContext->config.inputCfg.format = PCM_FORMAT_S15;
|
||||
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 = CHANNEL_STEREO;
|
||||
pContext->config.outputCfg.format = PCM_FORMAT_S15;
|
||||
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_configure(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, size_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:
|
||||
if (*pValueSize < sizeof(int16_t)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
*pValueSize = sizeof(int16_t);
|
||||
break;
|
||||
|
||||
case EQ_PARAM_LEVEL_RANGE:
|
||||
case EQ_PARAM_BAND_FREQ_RANGE:
|
||||
if (*pValueSize < 2 * sizeof(int32_t)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
*pValueSize = 2 * sizeof(int32_t);
|
||||
break;
|
||||
case EQ_PARAM_BAND_LEVEL:
|
||||
case EQ_PARAM_GET_BAND:
|
||||
case EQ_PARAM_CENTER_FREQ:
|
||||
if (*pValueSize < sizeof(int32_t)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
*pValueSize = sizeof(int32_t);
|
||||
break;
|
||||
|
||||
case EQ_PARAM_GET_PRESET_NAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (param) {
|
||||
case EQ_PARAM_NUM_BANDS:
|
||||
*(int16_t *)pValue = kNumBands;
|
||||
LOGV("Equalizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
|
||||
break;
|
||||
|
||||
case EQ_PARAM_LEVEL_RANGE:
|
||||
*(int32_t *)pValue = -9600;
|
||||
*((int32_t *)pValue + 1) = 4800;
|
||||
LOGV("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;
|
||||
}
|
||||
*(int32_t *)pValue = pEqualizer->getGain(param2);
|
||||
LOGV("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);
|
||||
LOGV("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));
|
||||
LOGV("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;
|
||||
*(int32_t *)pValue = pEqualizer->getMostRelevantBand(param2);
|
||||
LOGV("Equalizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d", param2, *(int32_t *)pValue);
|
||||
break;
|
||||
|
||||
case EQ_PARAM_CUR_PRESET:
|
||||
*(int16_t *)pValue = pEqualizer->getPreset();
|
||||
LOGV("Equalizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
|
||||
break;
|
||||
|
||||
case EQ_PARAM_GET_NUM_OF_PRESETS:
|
||||
*(int16_t *)pValue = pEqualizer->getNumPresets();
|
||||
LOGV("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;
|
||||
LOGV("Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d", param2, gEqualizerPresets[param2].name, *pValueSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGV("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 = *(int16_t *)pValue;
|
||||
|
||||
LOGV("setParameter() EQ_PARAM_CUR_PRESET %d", preset);
|
||||
if (preset >= pEqualizer->getNumPresets()) {
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
pEqualizer->setPreset(preset);
|
||||
pEqualizer->commit(true);
|
||||
break;
|
||||
case EQ_PARAM_BAND_LEVEL:
|
||||
band = *pParam;
|
||||
level = *(int32_t *)pValue;
|
||||
LOGV("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;
|
||||
default:
|
||||
LOGV("setParameter() invalid param %d", param);
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
} // end Equalizer_setParameter
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
||||
//
|
||||
//--- Effect Control Interface Implementation
|
||||
//
|
||||
|
||||
extern "C" int Equalizer_process(effect_interface_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;
|
||||
}
|
||||
|
||||
pContext->adapter.process(inBuffer->raw, outBuffer->raw, outBuffer->frameCount);
|
||||
return 0;
|
||||
} // end Equalizer_process
|
||||
|
||||
extern "C" int Equalizer_command(effect_interface_t self, int cmdCode, int cmdSize,
|
||||
void *pCmdData, int *replySize, void *pReplyData) {
|
||||
|
||||
android::EqualizerContext * pContext = (android::EqualizerContext *) self;
|
||||
int retsize;
|
||||
|
||||
if (pContext == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
android::AudioEqualizer * pEqualizer = pContext->pEqualizer;
|
||||
|
||||
LOGV("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_CONFIGURE:
|
||||
if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
|
||||
|| pReplyData == NULL || *replySize != sizeof(int)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
*(int *) pReplyData = Equalizer_configure(pContext,
|
||||
(effect_config_t *) pCmdData);
|
||||
break;
|
||||
case EFFECT_CMD_RESET:
|
||||
Equalizer_configure(pContext, &pContext->config);
|
||||
break;
|
||||
case EFFECT_CMD_GET_PARAM: {
|
||||
if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
|
||||
pReplyData == NULL || *replySize < (int) (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;
|
||||
LOGV("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: {
|
||||
LOGV("Equalizer_command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
|
||||
if (pCmdData == NULL || cmdSize < (int)(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;
|
||||
default:
|
||||
LOGW("Equalizer_command invalid command %d",cmdCode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// effect_interface_t interface implementation for equalizer effect
|
||||
const struct effect_interface_s gEqualizerInterface = {
|
||||
Equalizer_process,
|
||||
Equalizer_command
|
||||
};
|
||||
|
||||
|
2034
media/libeffects/EffectReverb.c
Normal file
2034
media/libeffects/EffectReverb.c
Normal file
File diff suppressed because it is too large
Load Diff
429
media/libeffects/EffectReverb.h
Normal file
429
media/libeffects/EffectReverb.h
Normal file
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTREVERB_H_
|
||||
#define ANDROID_EFFECTREVERB_H_
|
||||
|
||||
#include <media/EffectReverbApi.h>
|
||||
|
||||
|
||||
/*------------------------------------
|
||||
* defines
|
||||
*------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
CIRCULAR() calculates the array index using modulo arithmetic.
|
||||
The "trick" is that modulo arithmetic is simplified by masking
|
||||
the effective address where the mask is (2^n)-1. This only works
|
||||
if the buffer size is a power of two.
|
||||
*/
|
||||
#define CIRCULAR(base,offset,size) (uint32_t)( \
|
||||
( \
|
||||
((int32_t)(base)) + ((int32_t)(offset)) \
|
||||
) \
|
||||
& size \
|
||||
)
|
||||
|
||||
#define NUM_OUTPUT_CHANNELS 2
|
||||
#define OUTPUT_CHANNELS CHANNEL_STEREO
|
||||
|
||||
#define REVERB_BUFFER_SIZE_IN_SAMPLES_MAX 16384
|
||||
|
||||
#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid
|
||||
#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel
|
||||
|
||||
|
||||
// xfade parameters
|
||||
#define REVERB_XFADE_PERIOD_IN_SECONDS (double) (100.0 / 1000.0) // xfade once every this many seconds
|
||||
|
||||
|
||||
/**********/
|
||||
/* the entire synth uses various flags in a bit field */
|
||||
|
||||
/* if flag is set, synth reset has been requested */
|
||||
#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */
|
||||
#define MASK_REVERB_RESET_IS_REQUESTED 0x01
|
||||
#define MASK_REVERB_RESET_IS_NOT_REQUESTED (uint32_t)(~MASK_REVERB_RESET_IS_REQUESTED)
|
||||
|
||||
/*
|
||||
by default, we always want to update ALL channel parameters
|
||||
when we reset the synth (e.g., during GM ON)
|
||||
*/
|
||||
#define DEFAULT_REVERB_FLAGS 0x0
|
||||
|
||||
/* coefficients for generating sin, cos */
|
||||
#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */
|
||||
/*
|
||||
int32_t nPanG1 = +1.0 for sin
|
||||
int32_t nPanG1 = -1.0 for cos
|
||||
*/
|
||||
#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
|
||||
|
||||
/*************************************************************/
|
||||
// define the input injection points
|
||||
#define GUARD 5 // safety guard of this many samples
|
||||
|
||||
#define MAX_AP_TIME (int) ((20*65536)/1000) // delay time in time units (65536th of sec)
|
||||
#define MAX_DELAY_TIME (int) ((65*65536)/1000) // delay time in time units
|
||||
#define MAX_EARLY_TIME (int) ((65*65536)/1000) // delay time in time units
|
||||
|
||||
#define AP0_IN 0
|
||||
|
||||
|
||||
#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number
|
||||
#define DEFAULT_AP0_GAIN 19400
|
||||
#define DEFAULT_AP1_GAIN -19400
|
||||
|
||||
#define REVERB_DEFAULT_WET 32767
|
||||
#define REVERB_DEFAULT_DRY 0
|
||||
|
||||
#define REVERB_WET_MAX 32767
|
||||
#define REVERB_WET_MIN 0
|
||||
#define REVERB_DRY_MAX 32767
|
||||
#define REVERB_DRY_MIN 0
|
||||
|
||||
// constants for reverb density
|
||||
// The density expressed in permilles changes the Allpass delay in a linear manner in the range defined by
|
||||
// AP0_TIME_BASE to AP0_TIME_BASE + AP0_TIME_RANGE
|
||||
#define AP0_TIME_BASE (int)((9*65536)/1000)
|
||||
#define AP0_TIME_RANGE (int)((4*65536)/1000)
|
||||
#define AP1_TIME_BASE (int)((12*65536)/1000)
|
||||
#define AP1_TIME_RANGE (int)((8*65536)/1000)
|
||||
|
||||
// constants for reverb diffusion
|
||||
// The diffusion expressed in permilles changes the Allpass gain in a linear manner in the range defined by
|
||||
// AP0_GAIN_BASE to AP0_GAIN_BASE + AP0_GAIN_RANGE
|
||||
#define AP0_GAIN_BASE (int)(9830)
|
||||
#define AP0_GAIN_RANGE (int)(19660-9830)
|
||||
#define AP1_GAIN_BASE (int)(6553)
|
||||
#define AP1_GAIN_RANGE (int)(22936-6553)
|
||||
|
||||
|
||||
/* parameters for each allpass */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t m_zApOut; // delay offset for ap out
|
||||
|
||||
int16_t m_nApGain; // gain for ap
|
||||
|
||||
uint16_t m_zApIn; // delay offset for ap in
|
||||
|
||||
} allpass_object_t;
|
||||
|
||||
|
||||
/* parameters for early reflections */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out
|
||||
|
||||
int16_t m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap
|
||||
|
||||
} early_reflection_object_t;
|
||||
|
||||
//demo
|
||||
typedef struct
|
||||
{
|
||||
int16_t m_nRvbLpfFbk;
|
||||
int16_t m_nRvbLpfFwd;
|
||||
int16_t m_nRoomLpfFbk;
|
||||
int16_t m_nRoomLpfFwd;
|
||||
|
||||
int16_t m_nEarlyGain;
|
||||
int16_t m_nEarlyDelay;
|
||||
int16_t m_nLateGain;
|
||||
int16_t m_nLateDelay;
|
||||
|
||||
early_reflection_object_t m_sEarlyL;
|
||||
early_reflection_object_t m_sEarlyR;
|
||||
|
||||
uint16_t m_nMaxExcursion; //28
|
||||
int16_t m_nXfadeInterval;
|
||||
|
||||
int16_t m_nAp0_ApGain; //30
|
||||
int16_t m_nAp0_ApOut;
|
||||
int16_t m_nAp1_ApGain;
|
||||
int16_t m_nAp1_ApOut;
|
||||
int16_t m_nDiffusion;
|
||||
|
||||
int16_t m_rfu4;
|
||||
int16_t m_rfu5;
|
||||
int16_t m_rfu6;
|
||||
int16_t m_rfu7;
|
||||
int16_t m_rfu8;
|
||||
int16_t m_rfu9;
|
||||
int16_t m_rfu10; //43
|
||||
|
||||
} reverb_preset_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
reverb_preset_t m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets
|
||||
|
||||
} reverb_preset_bank_t;
|
||||
|
||||
|
||||
/* parameters for each reverb */
|
||||
typedef struct
|
||||
{
|
||||
/* update counter keeps track of when synth params need updating */
|
||||
/* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */
|
||||
int16_t m_nUpdateCounter;
|
||||
|
||||
uint16_t m_nBaseIndex; // base index for circular buffer
|
||||
|
||||
// reverb delay line offsets, allpass parameters, etc:
|
||||
|
||||
short m_nRevFbkR; // combine feedback reverb right out with dry left in
|
||||
short m_zOutLpfL; // left reverb output
|
||||
|
||||
allpass_object_t m_sAp0; // allpass 0 (left channel)
|
||||
|
||||
uint16_t m_zD0In; // delay offset for delay line D0 in
|
||||
|
||||
short m_nRevFbkL; // combine feedback reverb left out with dry right in
|
||||
short m_zOutLpfR; // right reverb output
|
||||
|
||||
allpass_object_t m_sAp1; // allpass 1 (right channel)
|
||||
|
||||
uint16_t m_zD1In; // delay offset for delay line D1 in
|
||||
|
||||
// delay output taps, notice criss cross order
|
||||
uint16_t m_zD0Self; // self feeds forward d0 --> d0
|
||||
|
||||
uint16_t m_zD1Cross; // cross feeds across d1 --> d0
|
||||
|
||||
uint16_t m_zD1Self; // self feeds forward d1 --> d1
|
||||
|
||||
uint16_t m_zD0Cross; // cross feeds across d0 --> d1
|
||||
|
||||
int16_t m_nSin; // gain for self taps
|
||||
|
||||
int16_t m_nCos; // gain for cross taps
|
||||
|
||||
int16_t m_nSinIncrement; // increment for gain
|
||||
|
||||
int16_t m_nCosIncrement; // increment for gain
|
||||
|
||||
int16_t m_nRvbLpfFwd; // reverb feedback lpf forward gain (includes scaling for mixer)
|
||||
|
||||
int16_t m_nRvbLpfFbk; // reverb feedback lpf feedback gain
|
||||
|
||||
int16_t m_nRoomLpfFwd; // room lpf forward gain (includes scaling for mixer)
|
||||
|
||||
int16_t m_nRoomLpfFbk; // room lpf feedback gain
|
||||
|
||||
uint16_t m_nXfadeInterval; // update/xfade after this many samples
|
||||
|
||||
uint16_t m_nXfadeCounter; // keep track of when to xfade
|
||||
|
||||
int16_t m_nPhase; // -1 <= m_nPhase < 1
|
||||
// but during sin,cos calculations
|
||||
// use m_nPhase/2
|
||||
|
||||
int16_t m_nPhaseIncrement; // add this to m_nPhase each frame
|
||||
|
||||
int16_t m_nNoise; // random noise sample
|
||||
|
||||
uint16_t m_nMaxExcursion; // the taps can excurse +/- this amount
|
||||
|
||||
uint16_t m_bUseNoise; // if TRUE, use noise as input signal
|
||||
|
||||
uint16_t m_bBypass; // if TRUE, then bypass reverb and copy input to output
|
||||
|
||||
int16_t m_nCurrentRoom; // preset number for current room
|
||||
|
||||
int16_t m_nNextRoom; // preset number for next room
|
||||
|
||||
int16_t m_nEarlyGain; // gain for early (widen) signal
|
||||
int16_t m_nEarlyDelay; // initial dealy for early (widen) signal
|
||||
int16_t m_nEarly0in;
|
||||
int16_t m_nEarly1in;
|
||||
int16_t m_nLateGain; // gain for late reverb
|
||||
int16_t m_nLateDelay;
|
||||
|
||||
int16_t m_nDiffusion;
|
||||
|
||||
early_reflection_object_t m_sEarlyL; // left channel early reflections
|
||||
early_reflection_object_t m_sEarlyR; // right channel early reflections
|
||||
|
||||
short m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES_MAX]; // one large delay line for all reverb elements
|
||||
|
||||
reverb_preset_t pPreset;
|
||||
|
||||
reverb_preset_bank_t m_sPreset;
|
||||
|
||||
//int8_t preset;
|
||||
uint32_t m_nSamplingRate;
|
||||
int32_t m_nUpdatePeriodInBits;
|
||||
int32_t m_nBufferMask;
|
||||
int32_t m_nUpdatePeriodInSamples;
|
||||
int32_t m_nDelay0Out;
|
||||
int32_t m_nDelay1Out;
|
||||
int16_t m_nCosWT_5KHz;
|
||||
|
||||
uint16_t m_Aux; // if TRUE, is connected as auxiliary effect
|
||||
uint16_t m_Preset; // if TRUE, expose preset revert interface
|
||||
|
||||
} reverb_object_t;
|
||||
|
||||
|
||||
|
||||
typedef struct reverb_module_s {
|
||||
const struct effect_interface_s *itfe;
|
||||
effect_config_t config;
|
||||
reverb_object_t context;
|
||||
} reverb_module_t;
|
||||
|
||||
/*------------------------------------
|
||||
* Effect API
|
||||
*------------------------------------
|
||||
*/
|
||||
int EffectQueryNumberEffects(int *pNumEffects);
|
||||
int EffectQueryNext(effect_descriptor_t *pDescriptor);
|
||||
int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface);
|
||||
int EffectRelease(effect_interface_t interface);
|
||||
|
||||
static int Reverb_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
|
||||
static int Reverb_Command(effect_interface_t self, int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
|
||||
|
||||
|
||||
/*------------------------------------
|
||||
* internal functions
|
||||
*------------------------------------
|
||||
*/
|
||||
|
||||
int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset);
|
||||
int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init);
|
||||
void Reverb_Reset(reverb_object_t *pReverb, bool init);
|
||||
|
||||
int Reverb_setParameter (reverb_object_t *pReverb, int32_t param, size_t size, void *pValue);
|
||||
int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, void *pValue);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* ReverbUpdateXfade
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Update the xfade parameters as required
|
||||
*
|
||||
* Inputs:
|
||||
* nNumSamplesToAdd - number of samples to write to buffer
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
*
|
||||
* Side Effects:
|
||||
* - xfade parameters will be changed
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static int ReverbUpdateXfade(reverb_object_t* pReverbData, int nNumSamplesToAdd);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* ReverbCalculateNoise
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Calculate a noise sample and limit its value
|
||||
*
|
||||
* Inputs:
|
||||
* Pointer to reverb context
|
||||
*
|
||||
* Outputs:
|
||||
* new limited noise value
|
||||
*
|
||||
* Side Effects:
|
||||
* - pReverbData->m_nNoise value is updated
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static uint16_t ReverbCalculateNoise(reverb_object_t *pReverbData);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* ReverbCalculateSinCos
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Calculate a new sin and cosine value based on the given phase
|
||||
*
|
||||
* Inputs:
|
||||
* nPhase - phase angle
|
||||
* pnSin - input old value, output new value
|
||||
* pnCos - input old value, output new value
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* Side Effects:
|
||||
* - *pnSin, *pnCos are updated
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static int ReverbCalculateSinCos(int16_t nPhase, int16_t *pnSin, int16_t *pnCos);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Reverb
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* apply reverb to the given signal
|
||||
*
|
||||
* Inputs:
|
||||
* nNu
|
||||
* pnSin - input old value, output new value
|
||||
* pnCos - input old value, output new value
|
||||
*
|
||||
* Outputs:
|
||||
* number of samples actually reverberated
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static int Reverb(reverb_object_t* pReverbData, int nNumSamplesToAdd, short *pOutputBuffer, short *pInputBuffer);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* ReverbReadInPresets()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose: sets global reverb preset bank to defaults
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static int ReverbReadInPresets(reverb_object_t* pReverbData);
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* ReverbUpdateRoom
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Update the room's preset parameters as required
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
*
|
||||
* Side Effects:
|
||||
* - reverb paramters (fbk, fwd, etc) will be changed
|
||||
* - m_nCurrentRoom := m_nNextRoom
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static int ReverbUpdateRoom(reverb_object_t* pReverbData, bool fullUpdate);
|
||||
|
||||
|
||||
static int ReverbComputeConstants(reverb_object_t *pReverbData, uint32_t samplingRate);
|
||||
|
||||
#endif /*ANDROID_EFFECTREVERB_H_*/
|
602
media/libeffects/EffectsFactory.c
Normal file
602
media/libeffects/EffectsFactory.c
Normal file
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* 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 "EffectsFactory"
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include "EffectsFactory.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
|
||||
static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
|
||||
static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
|
||||
static list_elem_t *gCurLib; // current library in enumeration process
|
||||
static list_elem_t *gCurEffect; // current effect in enumeration process
|
||||
|
||||
static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
|
||||
static int gInitDone; // true is global initialization has been preformed
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Local functions prototypes
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
static int init();
|
||||
static int loadLibrary(const char *libPath, int *handle);
|
||||
static int unloadLibrary(int handle);
|
||||
static int numEffectModules();
|
||||
static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
|
||||
static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect Control Interface functions
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
int Effect_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
|
||||
{
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
effect_entry_t *fx = (effect_entry_t *)self;
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
if (fx->lib == NULL) {
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
return -EPIPE;
|
||||
}
|
||||
pthread_mutex_lock(&fx->lib->lock);
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
|
||||
ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer);
|
||||
pthread_mutex_unlock(&fx->lib->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Effect_Command(effect_interface_t self, int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
|
||||
{
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
effect_entry_t *fx = (effect_entry_t *)self;
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
if (fx->lib == NULL) {
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
return -EPIPE;
|
||||
}
|
||||
pthread_mutex_lock(&fx->lib->lock);
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
|
||||
ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
|
||||
pthread_mutex_unlock(&fx->lib->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct effect_interface_s gInterface = {
|
||||
Effect_Process,
|
||||
Effect_Command
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect Factory Interface functions
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
int EffectQueryNumberEffects(int *pNumEffects)
|
||||
{
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (pNumEffects == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
*pNumEffects = numEffectModules();
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
LOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EffectQueryNext(effect_descriptor_t *pDescriptor)
|
||||
{
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (pDescriptor == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
ret = -ENOENT;
|
||||
while (gCurLib) {
|
||||
if (gCurEffect) {
|
||||
memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t));
|
||||
gCurEffect = gCurEffect->next;
|
||||
ret = 0;
|
||||
break;
|
||||
} else {
|
||||
gCurLib = gCurLib->next;
|
||||
gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
|
||||
}
|
||||
}
|
||||
char str[256];
|
||||
dumpEffectDescriptor(pDescriptor, str, 256);
|
||||
LOGV("EffectQueryNext() desc:%s", str);
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
|
||||
{
|
||||
lib_entry_t *l = NULL;
|
||||
effect_descriptor_t *d = NULL;
|
||||
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (pDescriptor == NULL || uuid == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
ret = findEffect(uuid, &l, &d);
|
||||
if (ret == 0) {
|
||||
memcpy(pDescriptor, d, sizeof(effect_descriptor_t));
|
||||
}
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EffectCreate(effect_uuid_t *uuid, effect_interface_t *pInterface)
|
||||
{
|
||||
list_elem_t *e = gLibraryList;
|
||||
lib_entry_t *l = NULL;
|
||||
effect_descriptor_t *d = NULL;
|
||||
effect_interface_t itfe;
|
||||
effect_entry_t *fx;
|
||||
int found = 0;
|
||||
int ret;
|
||||
|
||||
if (uuid == NULL || pInterface == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
|
||||
uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
|
||||
uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
|
||||
uuid->node[3],uuid->node[4],uuid->node[5]);
|
||||
|
||||
ret = init();
|
||||
|
||||
if (ret < 0) {
|
||||
LOGW("EffectCreate() init error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
|
||||
ret = findEffect(uuid, &l, &d);
|
||||
if (ret < 0){
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// create effect in library
|
||||
ret = l->createFx(uuid, &itfe);
|
||||
if (ret < 0) {
|
||||
LOGW("EffectCreate() library %s: could not create fx %s", l->path, d->name);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// add entry to effect list
|
||||
fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
|
||||
fx->subItfe = itfe;
|
||||
fx->itfe = (struct effect_interface_s *)&gInterface;
|
||||
fx->lib = l;
|
||||
|
||||
e = (list_elem_t *)malloc(sizeof(list_elem_t));
|
||||
e->object = fx;
|
||||
e->next = gEffectList;
|
||||
gEffectList = e;
|
||||
|
||||
*pInterface = (effect_interface_t)fx;
|
||||
|
||||
LOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pInterface, itfe, l->path);
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EffectRelease(effect_interface_t interface)
|
||||
{
|
||||
effect_entry_t *fx;
|
||||
list_elem_t *e1;
|
||||
list_elem_t *e2;
|
||||
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// remove effect from effect list
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
e1 = gEffectList;
|
||||
e2 = NULL;
|
||||
while (e1) {
|
||||
if (e1->object == interface) {
|
||||
if (e2) {
|
||||
e2->next = e1->next;
|
||||
} else {
|
||||
gEffectList = e1->next;
|
||||
}
|
||||
fx = (effect_entry_t *)e1->object;
|
||||
free(e1);
|
||||
break;
|
||||
}
|
||||
e2 = e1;
|
||||
e1 = e1->next;
|
||||
}
|
||||
if (e1 == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// release effect in library
|
||||
if (fx->lib == NULL) {
|
||||
LOGW("EffectRelease() fx %p library already unloaded", interface);
|
||||
} else {
|
||||
pthread_mutex_lock(&fx->lib->lock);
|
||||
fx->lib->releaseFx(fx->subItfe);
|
||||
pthread_mutex_unlock(&fx->lib->lock);
|
||||
}
|
||||
free(fx);
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EffectLoadLibrary(const char *libPath, int *handle)
|
||||
{
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (libPath == NULL || strnlen(libPath, PATH_MAX) >= PATH_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return loadLibrary(libPath, handle);
|
||||
}
|
||||
|
||||
int EffectUnloadLibrary(int handle)
|
||||
{
|
||||
int ret = init();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return unloadLibrary(handle);
|
||||
}
|
||||
|
||||
int EffectIsNullUuid(effect_uuid_t *uuid)
|
||||
{
|
||||
if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Local functions
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
int init() {
|
||||
struct dirent *ent;
|
||||
DIR *dir = NULL;
|
||||
char libpath[PATH_MAX];
|
||||
int hdl;
|
||||
|
||||
if (gInitDone) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&gLibLock, NULL);
|
||||
|
||||
// load built-in libraries
|
||||
dir = opendir(gEffectLibPath);
|
||||
if (dir == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
LOGV("init() reading file %s", ent->d_name);
|
||||
if ((strlen(ent->d_name) < 3) ||
|
||||
strncmp(ent->d_name, "lib", 3) != 0 ||
|
||||
strncmp(ent->d_name + strlen(ent->d_name) - 3, ".so", 3) != 0) {
|
||||
continue;
|
||||
}
|
||||
strcpy(libpath, gEffectLibPath);
|
||||
strcat(libpath, "/");
|
||||
strcat(libpath, ent->d_name);
|
||||
if (loadLibrary(libpath, &hdl) < 0) {
|
||||
LOGW("init() failed to load library %s",libpath);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
gInitDone = 1;
|
||||
LOGV("init() done");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int loadLibrary(const char *libPath, int *handle)
|
||||
{
|
||||
void *hdl;
|
||||
effect_QueryNumberEffects_t queryNumFx;
|
||||
effect_QueryNextEffect_t queryFx;
|
||||
effect_CreateEffect_t createFx;
|
||||
effect_ReleaseEffect_t releaseFx;
|
||||
int numFx;
|
||||
int fx;
|
||||
int ret;
|
||||
list_elem_t *e, *descHead = NULL;
|
||||
lib_entry_t *l;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*handle = 0;
|
||||
|
||||
hdl = dlopen(libPath, RTLD_NOW);
|
||||
if (hdl == 0) {
|
||||
LOGW("could open lib %s", libPath);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
// Check functions availability
|
||||
queryNumFx = (effect_QueryNumberEffects_t)dlsym(hdl, "EffectQueryNumberEffects");
|
||||
if (queryNumFx == NULL) {
|
||||
LOGW("could not get EffectQueryNumberEffects from lib %s", libPath);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
queryFx = (effect_QueryNextEffect_t)dlsym(hdl, "EffectQueryNext");
|
||||
if (queryFx == NULL) {
|
||||
LOGW("could not get EffectQueryNext from lib %s", libPath);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
createFx = (effect_CreateEffect_t)dlsym(hdl, "EffectCreate");
|
||||
if (createFx == NULL) {
|
||||
LOGW("could not get EffectCreate from lib %s", libPath);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
releaseFx = (effect_ReleaseEffect_t)dlsym(hdl, "EffectRelease");
|
||||
if (releaseFx == NULL) {
|
||||
LOGW("could not get EffectRelease from lib %s", libPath);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// load effect descriptors
|
||||
ret = queryNumFx(&numFx);
|
||||
if (ret) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (fx = 0; fx < numFx; fx++) {
|
||||
effect_descriptor_t *d = malloc(sizeof(effect_descriptor_t));
|
||||
if (d == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
ret = queryFx(d);
|
||||
if (ret == 0) {
|
||||
#if (LOG_NDEBUG==0)
|
||||
char s[256];
|
||||
dumpEffectDescriptor(d, s, 256);
|
||||
LOGV("loadLibrary() read descriptor %p:%s",d, s);
|
||||
#endif
|
||||
if (d->apiVersion != EFFECT_API_VERSION) {
|
||||
LOGW("Bad API version %04x on lib %s", d->apiVersion, libPath);
|
||||
free(d);
|
||||
continue;
|
||||
}
|
||||
e = malloc(sizeof(list_elem_t));
|
||||
if (e == NULL) {
|
||||
free(d);
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
e->object = d;
|
||||
e->next = descHead;
|
||||
descHead = e;
|
||||
} else {
|
||||
LOGW("Error querying effect # %d on lib %s", fx, libPath);
|
||||
}
|
||||
}
|
||||
// add entry for library in gLibraryList
|
||||
l = malloc(sizeof(lib_entry_t));
|
||||
l->handle = hdl;
|
||||
strncpy(l->path, libPath, PATH_MAX);
|
||||
l->createFx = createFx;
|
||||
l->releaseFx = releaseFx;
|
||||
l->effects = descHead;
|
||||
pthread_mutex_init(&l->lock, NULL);
|
||||
|
||||
e = malloc(sizeof(list_elem_t));
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
e->next = gLibraryList;
|
||||
e->object = l;
|
||||
gLibraryList = e;
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
LOGV("loadLibrary() linked library %p", l);
|
||||
|
||||
*handle = (int)hdl;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LOGW("loadLibrary() error: %d on lib: %s", ret, libPath);
|
||||
while (descHead) {
|
||||
free(descHead->object);
|
||||
e = descHead->next;
|
||||
free(descHead);
|
||||
descHead = e;;
|
||||
}
|
||||
dlclose(hdl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unloadLibrary(int handle)
|
||||
{
|
||||
void *hdl;
|
||||
int ret;
|
||||
list_elem_t *el1, *el2;
|
||||
lib_entry_t *l;
|
||||
effect_entry_t *fx;
|
||||
|
||||
pthread_mutex_lock(&gLibLock);
|
||||
el1 = gLibraryList;
|
||||
el2 = NULL;
|
||||
while (el1) {
|
||||
l = (lib_entry_t *)el1->object;
|
||||
if (handle == (int)l->handle) {
|
||||
if (el2) {
|
||||
el2->next = el1->next;
|
||||
} else {
|
||||
gLibraryList = el1->next;
|
||||
}
|
||||
free(el1);
|
||||
break;
|
||||
}
|
||||
el2 = el1;
|
||||
el1 = el1->next;
|
||||
}
|
||||
pthread_mutex_unlock(&gLibLock);
|
||||
if (el1 == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
// clear effect descriptor list
|
||||
el1 = l->effects;
|
||||
while (el1) {
|
||||
free(el1->object);
|
||||
el2 = el1->next;
|
||||
free(el1);
|
||||
el1 = el2;
|
||||
}
|
||||
|
||||
// disable all effects from this library
|
||||
pthread_mutex_lock(&l->lock);
|
||||
el1 = gEffectList;
|
||||
while (el1) {
|
||||
fx = (effect_entry_t *)el1->object;
|
||||
if (fx->lib == l) {
|
||||
fx->lib = NULL;
|
||||
}
|
||||
el1 = el1->next;
|
||||
}
|
||||
pthread_mutex_unlock(&l->lock);
|
||||
|
||||
dlclose(l->handle);
|
||||
free(l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int numEffectModules() {
|
||||
list_elem_t *e = gLibraryList;
|
||||
int cnt = 0;
|
||||
|
||||
// Reset pointers for EffectQueryNext()
|
||||
gCurLib = e;
|
||||
if (e) {
|
||||
gCurEffect = ((lib_entry_t *)e->object)->effects;
|
||||
}
|
||||
while (e) {
|
||||
lib_entry_t *l = (lib_entry_t *)e->object;
|
||||
list_elem_t *efx = l->effects;
|
||||
while (efx) {
|
||||
cnt++;
|
||||
efx = efx->next;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc)
|
||||
{
|
||||
list_elem_t *e = gLibraryList;
|
||||
lib_entry_t *l = NULL;
|
||||
effect_descriptor_t *d = NULL;
|
||||
int found = 0;
|
||||
int ret = 0;
|
||||
|
||||
while (e && !found) {
|
||||
l = (lib_entry_t *)e->object;
|
||||
list_elem_t *efx = l->effects;
|
||||
while (efx) {
|
||||
d = (effect_descriptor_t *)efx->object;
|
||||
if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
efx = efx->next;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
if (!found) {
|
||||
LOGV("findEffect() effect not found");
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
LOGV("findEffect() found effect: %s in lib %s", d->name, l->path);
|
||||
*lib = l;
|
||||
*desc = d;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) {
|
||||
char s[256];
|
||||
|
||||
snprintf(str, len, "\nEffect Descriptor %p:\n", desc);
|
||||
sprintf(s, "- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
|
||||
desc->uuid.timeLow, desc->uuid.timeMid, desc->uuid.timeHiAndVersion,
|
||||
desc->uuid.clockSeq, desc->uuid.node[0], desc->uuid.node[1],desc->uuid.node[2],
|
||||
desc->uuid.node[3],desc->uuid.node[4],desc->uuid.node[5]);
|
||||
strncat(str, s, len);
|
||||
sprintf(s, "- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
|
||||
desc->type.timeLow, desc->type.timeMid, desc->type.timeHiAndVersion,
|
||||
desc->type.clockSeq, desc->type.node[0], desc->type.node[1],desc->type.node[2],
|
||||
desc->type.node[3],desc->type.node[4],desc->type.node[5]);
|
||||
strncat(str, s, len);
|
||||
sprintf(s, "- apiVersion: %04X\n- flags: %08X\n",
|
||||
desc->apiVersion, desc->flags);
|
||||
strncat(str, s, len);
|
||||
sprintf(s, "- name: %s\n", desc->name);
|
||||
strncat(str, s, len);
|
||||
sprintf(s, "- implementor: %s\n", desc->implementor);
|
||||
strncat(str, s, len);
|
||||
}
|
||||
|
55
media/libeffects/EffectsFactory.h
Normal file
55
media/libeffects/EffectsFactory.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTSFACTORY_H_
|
||||
#define ANDROID_EFFECTSFACTORY_H_
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <pthread.h>
|
||||
#include <dirent.h>
|
||||
#include <media/EffectFactoryApi.h>
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct list_elem_s {
|
||||
void *object;
|
||||
struct list_elem_s *next;
|
||||
} list_elem_t;
|
||||
|
||||
typedef struct lib_entry_s {
|
||||
char path[PATH_MAX];
|
||||
void *handle;
|
||||
effect_CreateEffect_t createFx;
|
||||
effect_ReleaseEffect_t releaseFx;
|
||||
list_elem_t *effects; //list of effect_descriptor_t
|
||||
pthread_mutex_t lock;
|
||||
} lib_entry_t;
|
||||
|
||||
typedef struct effect_entry_s {
|
||||
struct effect_interface_s *itfe;
|
||||
effect_interface_t subItfe;
|
||||
lib_entry_t *lib;
|
||||
} effect_entry_t;
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_EFFECTSFACTORY_H_*/
|
143
media/libeffects/EffectsMath.c
Normal file
143
media/libeffects/EffectsMath.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 "EFFECTSMATH"
|
||||
//#define LOG_NDEBUG 0
|
||||
#include <cutils/log.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "EffectsMath.h"
|
||||
|
||||
// gLogTab contains pre-calculated values of log2(1 + ai5*2^-1 + ai4*2^-2 + ai3*2^-3 + ai2*2^-4 + ai1*2^-5 + ai0*2^-6)
|
||||
// for integers in the range 0 to 63 (i = ai5*2^5 + ai4*2^4 + ai3*2^3 + ai2*2^2 + ai1*2^1 + ai0*2^0)
|
||||
// It is used for a better than piece wise approximation of lin to log2 conversion
|
||||
|
||||
static const uint16_t gLogTab[] =
|
||||
{
|
||||
0, 733, 1455, 2166,
|
||||
2866, 3556, 4236, 4907,
|
||||
5568, 6220, 6863, 7498,
|
||||
8124, 8742, 9352, 9954,
|
||||
10549, 11136, 11716, 12289,
|
||||
12855, 13415, 13968, 14514,
|
||||
15055, 15589, 16117, 16639,
|
||||
17156, 17667, 18173, 18673,
|
||||
19168, 19658, 20143, 20623,
|
||||
21098, 21568, 22034, 22495,
|
||||
22952, 23404, 23852, 24296,
|
||||
24736, 25172, 25604, 26031,
|
||||
26455, 26876, 27292, 27705,
|
||||
28114, 28520, 28922, 29321,
|
||||
29717, 30109, 30498, 30884,
|
||||
31267, 31647, 32024, 32397,
|
||||
32768
|
||||
};
|
||||
|
||||
int32_t Effects_log2(uint32_t x) {
|
||||
int32_t exp = 31 - __builtin_clz(x);
|
||||
uint32_t segStart = x >> (exp - 6);
|
||||
uint32_t i = segStart & 0x3F;
|
||||
int32_t log = (int32_t)gLogTab[i];
|
||||
int32_t logEnd = (int32_t)gLogTab[i+1];
|
||||
segStart <<= exp - 6;
|
||||
|
||||
return (exp << 15) + log + (((x - segStart) * (logEnd - log)) >> (exp - 6));
|
||||
}
|
||||
|
||||
// gExpTab[i] = (2^(i>>6)) << 22
|
||||
static const uint32_t gExpTab[] = {
|
||||
4194304, 4239977, 4286147, 4332820,
|
||||
4380002, 4427697, 4475911, 4524651,
|
||||
4573921, 4623728, 4674077, 4724974,
|
||||
4776426, 4828438, 4881016, 4934167,
|
||||
4987896, 5042211, 5097117, 5152621,
|
||||
5208729, 5265449, 5322786, 5380747,
|
||||
5439339, 5498570, 5558445, 5618973,
|
||||
5680159, 5742012, 5804539, 5867746,
|
||||
5931642, 5996233, 6061528, 6127533,
|
||||
6194258, 6261709, 6329894, 6398822,
|
||||
6468501, 6538938, 6610143, 6682122,
|
||||
6754886, 6828442, 6902799, 6977965,
|
||||
7053950, 7130763, 7208412, 7286906,
|
||||
7366255, 7446469, 7527555, 7609525,
|
||||
7692387, 7776152, 7860829, 7946428,
|
||||
8032959, 8120432, 8208857, 8298246,
|
||||
8388608
|
||||
};
|
||||
|
||||
|
||||
uint32_t Effects_exp2(int32_t x) {
|
||||
int32_t i = x >> 15;
|
||||
assert(i < 32);
|
||||
x &= (1 << 15) - 1;
|
||||
int32_t j = x >> 9;
|
||||
x &= (1 << 9) - 1;
|
||||
uint32_t exp = gExpTab[j];
|
||||
uint32_t expEnd = gExpTab[j+1];
|
||||
|
||||
return ((exp << 9) + (expEnd - exp) * x) >> (31 - i);
|
||||
}
|
||||
|
||||
|
||||
int16_t Effects_MillibelsToLinear16 (int32_t nGain)
|
||||
{
|
||||
nGain = ((nGain + MB_TO_LIN_K1) << 15 ) / MB_TO_LIN_K2;
|
||||
uint32_t exp2 = Effects_exp2(nGain);
|
||||
|
||||
if (exp2 > 32767) exp2 = 32767;
|
||||
|
||||
return (int16_t)exp2;
|
||||
}
|
||||
|
||||
|
||||
int16_t Effects_Linear16ToMillibels (int32_t nGain)
|
||||
{
|
||||
return (int16_t)(((MB_TO_LIN_K2*Effects_log2(nGain))>>15)-MB_TO_LIN_K1);
|
||||
}
|
||||
|
||||
|
||||
int32_t Effects_Sqrt(int32_t in)
|
||||
{
|
||||
int32_t tmp;
|
||||
int32_t out = 0;
|
||||
int32_t i;
|
||||
int32_t j;
|
||||
|
||||
|
||||
if (in == 0) return 0;
|
||||
|
||||
if (in >= 0x10000000)
|
||||
{
|
||||
out = 0x4000;
|
||||
in -= 0x10000000;
|
||||
}
|
||||
|
||||
j = 32 - __builtin_clz(in);
|
||||
|
||||
if (j & 1) j++;
|
||||
j >>= 1;
|
||||
|
||||
for (i = j; i > 0; i--) {
|
||||
tmp = (out << i) + (1 << ((i - 1)*2));
|
||||
if (in >= tmp)
|
||||
{
|
||||
out += 1 << (i-1);
|
||||
in -= tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
424
media/libeffects/EffectsMath.h
Normal file
424
media/libeffects/EffectsMath.h
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTSMATH_H_
|
||||
#define ANDROID_EFFECTSMATH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** coefs for pan, generates sin, cos */
|
||||
#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */
|
||||
#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
|
||||
|
||||
/*
|
||||
coefficients for approximating
|
||||
2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3
|
||||
where x is a int.frac number representing number of octaves.
|
||||
Actually, we approximate only the 2^(frac) using the power series
|
||||
and implement the 2^(int) as a shift, so that
|
||||
2^x == 2^(int.frac) == 2^(int) * 2^(fract)
|
||||
== (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int)
|
||||
|
||||
The gn2toX.. were generated using a best fit for a 3rd
|
||||
order polynomial, instead of taking the coefficients from
|
||||
a truncated Taylor (or Maclaurin?) series.
|
||||
*/
|
||||
|
||||
#define GN2_TO_X0 32768 /* 1 */
|
||||
#define GN2_TO_X1 22833 /* 0.696807861328125 */
|
||||
#define GN2_TO_X2 7344 /* 0.22412109375 */
|
||||
#define GN2_TO_X3 2588 /* 0.0789794921875 */
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Fixed Point Math
|
||||
*----------------------------------------------------------------------------
|
||||
* These macros are used for fixed point multiplies. If the processor
|
||||
* supports fixed point multiplies, replace these macros with inline
|
||||
* assembly code to improve performance.
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */
|
||||
#define FMUL_15x15(a,b) \
|
||||
/*lint -e(704) <avoid multiply for performance>*/ \
|
||||
(((int32_t)(a) * (int32_t)(b)) >> 15)
|
||||
|
||||
/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */
|
||||
#define FMUL_7x7(a,b) \
|
||||
/*lint -e(704) <avoid multiply for performance>*/ \
|
||||
(((int32_t)(a) * (int32_t)(b) ) << 1)
|
||||
|
||||
/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */
|
||||
#define FMUL_8x8(a,b) \
|
||||
/*lint -e(704) <avoid multiply for performance>*/ \
|
||||
(((int32_t)(a) * (int32_t)(b) ) >> 1)
|
||||
|
||||
/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */
|
||||
#define FMUL_8x15(a,b) \
|
||||
/*lint -e(704) <avoid divide for performance>*/ \
|
||||
(((int32_t)((a) << 7) * (int32_t)(b)) >> 15)
|
||||
|
||||
/* macros for fractional phase accumulator */
|
||||
/*
|
||||
Note: changed the _U32 to _I32 on 03/14/02. This should not
|
||||
affect the phase calculations, and should allow us to reuse these
|
||||
macros for other audio sample related math.
|
||||
*/
|
||||
#define HARDWARE_BIT_WIDTH 32
|
||||
|
||||
#define NUM_PHASE_INT_BITS 1
|
||||
#define NUM_PHASE_FRAC_BITS 15
|
||||
|
||||
#define PHASE_FRAC_MASK (uint32_t) ((0x1L << NUM_PHASE_FRAC_BITS) -1)
|
||||
|
||||
#define GET_PHASE_INT_PART(x) (uint32_t)((uint32_t)(x) >> NUM_PHASE_FRAC_BITS)
|
||||
#define GET_PHASE_FRAC_PART(x) (uint32_t)((uint32_t)(x) & PHASE_FRAC_MASK)
|
||||
|
||||
#define DEFAULT_PHASE_FRAC 0
|
||||
#define DEFAULT_PHASE_INT 0
|
||||
|
||||
/*
|
||||
Linear interpolation calculates:
|
||||
output = (1-frac) * sample[n] + (frac) * sample[n+1]
|
||||
|
||||
where conceptually 0 <= frac < 1
|
||||
|
||||
For a fixed point implementation, frac is actually an integer value
|
||||
with an implied binary point one position to the left. The value of
|
||||
one (unity) is given by PHASE_ONE
|
||||
one half and one quarter are useful for 4-point linear interp.
|
||||
*/
|
||||
#define PHASE_ONE (int32_t) (0x1L << NUM_PHASE_FRAC_BITS)
|
||||
|
||||
/*
|
||||
Multiply the signed audio sample by the unsigned fraction.
|
||||
- a is the signed audio sample
|
||||
- b is the unsigned fraction (cast to signed int as long as coef
|
||||
uses (n-1) or less bits, where n == hardware bit width)
|
||||
*/
|
||||
#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 <avoid divide for performance>*/ \
|
||||
(int32_t)( \
|
||||
( \
|
||||
((int32_t)(audio)) * ((int32_t)(coef)) \
|
||||
) \
|
||||
>> NUM_PHASE_FRAC_BITS \
|
||||
) \
|
||||
/* lint +704 <restore checking>*/
|
||||
|
||||
/* wet / dry calculation macros */
|
||||
#define NUM_WET_DRY_FRAC_BITS 7 // 15
|
||||
#define NUM_WET_DRY_INT_BITS 9 // 1
|
||||
|
||||
/* define a 1.0 */
|
||||
#define WET_DRY_ONE (int32_t) ((0x1L << NUM_WET_DRY_FRAC_BITS))
|
||||
#define WET_DRY_MINUS_ONE (int32_t) (~WET_DRY_ONE)
|
||||
#define WET_DRY_FULL_SCALE (int32_t) (WET_DRY_ONE - 1)
|
||||
|
||||
#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) <avoid divide for performance>*/ \
|
||||
(int32_t)( \
|
||||
( \
|
||||
((int32_t)(audio)) * ((int32_t)(coef)) \
|
||||
) \
|
||||
>> NUM_WET_DRY_FRAC_BITS \
|
||||
)
|
||||
|
||||
/* Envelope 1 (EG1) calculation macros */
|
||||
#define NUM_EG1_INT_BITS 1
|
||||
#define NUM_EG1_FRAC_BITS 15
|
||||
|
||||
/* the max positive gain used in the synth for EG1 */
|
||||
/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas
|
||||
converter, otherwise, the values we read from the .eas file are bogus. */
|
||||
#define SYNTH_FULL_SCALE_EG1_GAIN (int32_t) ((0x1L << NUM_EG1_FRAC_BITS) -1)
|
||||
|
||||
/* define a 1.0 */
|
||||
#define EG1_ONE (int32_t) ((0x1L << NUM_EG1_FRAC_BITS))
|
||||
#define EG1_MINUS_ONE (int32_t) (~SYNTH_FULL_SCALE_EG1_GAIN)
|
||||
|
||||
#define EG1_HALF (int32_t) (EG1_ONE/2)
|
||||
#define EG1_MINUS_HALF (int32_t) (EG1_MINUS_ONE/2)
|
||||
|
||||
/*
|
||||
We implement the EG1 using a linear gain value, which means that the
|
||||
attack segment is handled by incrementing (adding) the linear gain.
|
||||
However, EG1 treats the Decay, Sustain, and Release differently than
|
||||
the Attack portion. For Decay, Sustain, and Release, the gain is
|
||||
linear on dB scale, which is equivalent to exponential damping on
|
||||
a linear scale. Because we use a linear gain for EG1, we implement
|
||||
the Decay and Release as multiplication (instead of incrementing
|
||||
as we did for the attack segment).
|
||||
Therefore, we need the following macro to implement the multiplication
|
||||
(i.e., exponential damping) during the Decay and Release segments of
|
||||
the EG1
|
||||
*/
|
||||
#define MULT_EG1_EG1(gain,damping) /*lint -e(704) <avoid divide for performance>*/ \
|
||||
(int32_t)( \
|
||||
( \
|
||||
((int32_t)(gain)) * ((int32_t)(damping)) \
|
||||
) \
|
||||
>> NUM_EG1_FRAC_BITS \
|
||||
)
|
||||
|
||||
// Use the following macro specifically for the filter, when multiplying
|
||||
// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow
|
||||
// in certain conditions because we store b1 as a 1.15 value.
|
||||
// Instead, we could store b1 as b1p (b1' == b1 "prime") where
|
||||
// b1p == b1/2, thus ensuring no potential overflow for b1p because
|
||||
// 0 <= |b1p| < 1
|
||||
// However, during the filter calculation, we must account for the fact
|
||||
// that we are using b1p instead of b1, and thereby multiply by
|
||||
// an extra factor of 2. Rather than multiply by an extra factor of 2,
|
||||
// we can instead shift the result right by one less, hence the
|
||||
// modified shift right value of (NUM_EG1_FRAC_BITS -1)
|
||||
#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) <avoid divide for performance>*/ \
|
||||
(int32_t)( \
|
||||
( \
|
||||
((int32_t)(gain)) * ((int32_t)(damping)) \
|
||||
) \
|
||||
>> (NUM_EG1_FRAC_BITS -1) \
|
||||
)
|
||||
|
||||
#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \
|
||||
((int32_t)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \
|
||||
((int32_t)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x);
|
||||
|
||||
|
||||
/* use "digital cents" == "dents" instead of cents */
|
||||
/* we coudl re-use the phase frac macros, but if we do,
|
||||
we must change the phase macros to cast to _I32 instead of _U32,
|
||||
because using a _U32 cast causes problems when shifting the exponent
|
||||
for the 2^x calculation, because right shift a negative values MUST
|
||||
be sign extended, or else the 2^x calculation is wrong */
|
||||
|
||||
/* use "digital cents" == "dents" instead of cents */
|
||||
#define NUM_DENTS_FRAC_BITS 12
|
||||
#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS)
|
||||
|
||||
#define DENTS_FRAC_MASK (int32_t) ((0x1L << NUM_DENTS_FRAC_BITS) -1)
|
||||
|
||||
#define GET_DENTS_INT_PART(x) /*lint -e(704) <avoid divide for performance>*/ \
|
||||
(int32_t)((int32_t)(x) >> NUM_DENTS_FRAC_BITS)
|
||||
|
||||
#define GET_DENTS_FRAC_PART(x) (int32_t)((int32_t)(x) & DENTS_FRAC_MASK)
|
||||
|
||||
#define DENTS_ONE (int32_t) (0x1L << NUM_DENTS_FRAC_BITS)
|
||||
|
||||
/* use CENTS_TO_DENTS to convert a value in cents to dents */
|
||||
#define CENTS_TO_DENTS (int32_t) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \
|
||||
|
||||
|
||||
/*
|
||||
For gain, the LFO generates a value that modulates in terms
|
||||
of dB. However, we use a linear gain value, so we must convert
|
||||
the LFO value in dB to a linear gain. Normally, we would use
|
||||
linear gain = 10^x, where x = LFO value in dB / 20.
|
||||
Instead, we implement 10^x using our 2^x approximation.
|
||||
because
|
||||
|
||||
10^x = 2^(log2(10^x)) = 2^(x * log2(10))
|
||||
|
||||
so we need to multiply by log2(10) which is just a constant.
|
||||
Ah, but just wait -- our 2^x actually doesn't exactly implement
|
||||
2^x, but it actually assumes that the input is in cents, and within
|
||||
the 2^x approximation converts its input from cents to octaves
|
||||
by dividing its input by 1200.
|
||||
|
||||
So, in order to convert the LFO gain value in dB to something
|
||||
that our existing 2^x approximation can use, multiply the LFO gain
|
||||
by log2(10) * 1200 / 20
|
||||
|
||||
The divide by 20 helps convert dB to linear gain, and we might
|
||||
as well incorporate that operation into this conversion.
|
||||
Of course, we need to keep some fractional bits, so multiply
|
||||
the constant by NUM_EG1_FRAC_BITS
|
||||
*/
|
||||
|
||||
/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */
|
||||
#if 0
|
||||
#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */
|
||||
|
||||
#define DOUBLE_LFO_GAIN_TO_CENTS (double) \
|
||||
( \
|
||||
(DOUBLE_LOG2_10) * \
|
||||
1200.0 / \
|
||||
20.0 \
|
||||
)
|
||||
|
||||
#define LFO_GAIN_TO_CENTS (int32_t) \
|
||||
( \
|
||||
DOUBLE_LFO_GAIN_TO_CENTS * \
|
||||
(0x1L << NUM_EG1_FRAC_BITS) \
|
||||
)
|
||||
#endif
|
||||
|
||||
#define LFO_GAIN_TO_CENTS (int32_t) (1671981156L >> (23 - NUM_EG1_FRAC_BITS))
|
||||
|
||||
|
||||
#define MULT_DENTS_COEF(dents,coef) /*lint -e704 <avoid divide for performance>*/ \
|
||||
(int32_t)( \
|
||||
( \
|
||||
((int32_t)(dents)) * ((int32_t)(coef)) \
|
||||
) \
|
||||
>> NUM_DENTS_FRAC_BITS \
|
||||
) \
|
||||
/* lint +e704 <restore checking>*/
|
||||
|
||||
|
||||
/* we use 16-bits in the PC per audio sample */
|
||||
#define BITS_PER_AUDIO_SAMPLE 16
|
||||
|
||||
/* we define 1 as 1.0 - 1 LSbit */
|
||||
#define DISTORTION_ONE (int32_t)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1)
|
||||
#define DISTORTION_MINUS_ONE (int32_t)(~DISTORTION_ONE)
|
||||
|
||||
/* drive coef is given as int.frac */
|
||||
#define NUM_DRIVE_COEF_INT_BITS 1
|
||||
#define NUM_DRIVE_COEF_FRAC_BITS 4
|
||||
|
||||
#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) <avoid divide for performance>*/ \
|
||||
(int32_t) ( \
|
||||
( \
|
||||
((int32_t)(audio)) * ((int32_t)(drive)) \
|
||||
) \
|
||||
>> NUM_DRIVE_COEF_FRAC_BITS \
|
||||
)
|
||||
|
||||
#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) <avoid divide for performance>*/ \
|
||||
(int32_t) ( \
|
||||
( \
|
||||
((int32_t)(audio1)) * ((int32_t)(audio2)) \
|
||||
) \
|
||||
>> (BITS_PER_AUDIO_SAMPLE-1) \
|
||||
)
|
||||
|
||||
#define SATURATE(x) \
|
||||
((((int32_t)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \
|
||||
(((int32_t)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((int32_t)(x)));
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Effects_log2()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Fixed-point log2 function.
|
||||
*
|
||||
* Inputs:
|
||||
* Input is interpreted as an integer (should not be 0).
|
||||
*
|
||||
* Outputs:
|
||||
* Output is in 15-bit precision.
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
int32_t Effects_log2(uint32_t x);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Effects_exp2()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Fixed-point radix-2 exponent.
|
||||
*
|
||||
* Inputs:
|
||||
* Input is in 15-bit precision. Must be non-negative and less than 32.
|
||||
*
|
||||
* Outputs:
|
||||
* Output is an integer.
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
uint32_t Effects_exp2(int32_t x);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Effects_MillibelsToLinear16()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Transform gain in millibels to linear gain multiplier:
|
||||
*
|
||||
* mB = 2000*log(lin/32767)
|
||||
* => lin = 2^((mB+2000*log(32767))/2000*log(2))
|
||||
* => lin = Effects_exp2(((mB + K1) << 15) / K2)
|
||||
* with:
|
||||
* K1 = 2000*log(32767) and K2 = 2000*log(2)
|
||||
*
|
||||
* Inputs:
|
||||
* nGain - log scale value in millibels.
|
||||
*
|
||||
* Outputs:
|
||||
* Returns a 16-bit linear value approximately equal to 2^(nGain/1024)
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
#define MB_TO_LIN_K1 9031
|
||||
#define MB_TO_LIN_K2 602
|
||||
int16_t Effects_MillibelsToLinear16 (int32_t nGain);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Effects_Linear16ToMillibels()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Transform linear gain multiplier to millibels
|
||||
* mB = 2000*log(lin/32767)
|
||||
* = 2000*log(2)*log2(lin)-2000*log(32767)
|
||||
* => mB = K1*Effects_log2(lin) + K2
|
||||
* with:
|
||||
* K1 = 2000*log(2) and K2 = -2000*log(32767)
|
||||
*
|
||||
* Inputs:
|
||||
* nGain - linear multiplier ranging form 0 to 32767 (corresponding to [0 1] gain range).
|
||||
*
|
||||
* Outputs:
|
||||
* Returns a 16-bit log value expressed in milllibels.
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
int16_t Effects_Linear16ToMillibels (int32_t nGain);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Effects_Sqrt()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Returns the square root of the argument given.
|
||||
*
|
||||
* Inputs:
|
||||
* in - positive number in the range 0 - 2^28
|
||||
*
|
||||
* Outputs:
|
||||
* Returned value: square root of in.
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
int32_t Effects_Sqrt(int32_t in);
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /*ANDROID_EFFECTSMATH_H_*/
|
||||
|
Reference in New Issue
Block a user