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/RefBase.h>
|
||||||
#include <utils/threads.h>
|
#include <utils/threads.h>
|
||||||
#include <media/IAudioFlinger.h>
|
#include <media/IAudioFlinger.h>
|
||||||
|
#include <media/AudioCommon.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@ -50,8 +51,8 @@ public:
|
|||||||
|
|
||||||
// Audio sub formats (see AudioSystem::audio_format).
|
// Audio sub formats (see AudioSystem::audio_format).
|
||||||
enum pcm_sub_format {
|
enum pcm_sub_format {
|
||||||
PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
|
PCM_SUB_16_BIT = PCM_FORMAT_S15, // must be 1 for backward compatibility
|
||||||
PCM_SUB_8_BIT = 0x2, // must be 2 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
|
// 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
|
// Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java
|
||||||
enum audio_channels {
|
enum audio_channels {
|
||||||
// output channels
|
// output channels
|
||||||
CHANNEL_OUT_FRONT_LEFT = 0x4,
|
CHANNEL_OUT_FRONT_LEFT = CHANNEL_FRONT_LEFT,
|
||||||
CHANNEL_OUT_FRONT_RIGHT = 0x8,
|
CHANNEL_OUT_FRONT_RIGHT = CHANNEL_FRONT_RIGHT,
|
||||||
CHANNEL_OUT_FRONT_CENTER = 0x10,
|
CHANNEL_OUT_FRONT_CENTER = CHANNEL_FRONT_CENTER,
|
||||||
CHANNEL_OUT_LOW_FREQUENCY = 0x20,
|
CHANNEL_OUT_LOW_FREQUENCY = CHANNEL_LOW_FREQUENCY,
|
||||||
CHANNEL_OUT_BACK_LEFT = 0x40,
|
CHANNEL_OUT_BACK_LEFT = CHANNEL_BACK_LEFT,
|
||||||
CHANNEL_OUT_BACK_RIGHT = 0x80,
|
CHANNEL_OUT_BACK_RIGHT = CHANNEL_BACK_RIGHT,
|
||||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
|
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = CHANNEL_FRONT_LEFT_OF_CENTER,
|
||||||
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
|
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = CHANNEL_FRONT_RIGHT_OF_CENTER,
|
||||||
CHANNEL_OUT_BACK_CENTER = 0x400,
|
CHANNEL_OUT_BACK_CENTER = CHANNEL_BACK_CENTER,
|
||||||
CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
|
CHANNEL_OUT_MONO = CHANNEL_MONO,
|
||||||
CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
|
CHANNEL_OUT_STEREO = CHANNEL_STEREO,
|
||||||
CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
CHANNEL_OUT_QUAD = CHANNEL_QUAD,
|
||||||
CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
|
CHANNEL_OUT_SURROUND = CHANNEL_SURROUND,
|
||||||
CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
CHANNEL_OUT_5POINT1 = CHANNEL_5POINT1,
|
||||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
|
CHANNEL_OUT_7POINT1 = CHANNEL_7POINT1,
|
||||||
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_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
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_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),
|
CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER),
|
||||||
@ -240,17 +236,17 @@ public:
|
|||||||
|
|
||||||
enum audio_devices {
|
enum audio_devices {
|
||||||
// output devices
|
// output devices
|
||||||
DEVICE_OUT_EARPIECE = 0x1,
|
DEVICE_OUT_EARPIECE = DEVICE_EARPIECE,
|
||||||
DEVICE_OUT_SPEAKER = 0x2,
|
DEVICE_OUT_SPEAKER = DEVICE_SPEAKER,
|
||||||
DEVICE_OUT_WIRED_HEADSET = 0x4,
|
DEVICE_OUT_WIRED_HEADSET = DEVICE_WIRED_HEADSET,
|
||||||
DEVICE_OUT_WIRED_HEADPHONE = 0x8,
|
DEVICE_OUT_WIRED_HEADPHONE = DEVICE_WIRED_HEADPHONE,
|
||||||
DEVICE_OUT_BLUETOOTH_SCO = 0x10,
|
DEVICE_OUT_BLUETOOTH_SCO = DEVICE_BLUETOOTH_SCO,
|
||||||
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
|
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = DEVICE_BLUETOOTH_SCO_HEADSET,
|
||||||
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
|
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = DEVICE_BLUETOOTH_SCO_CARKIT,
|
||||||
DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
|
DEVICE_OUT_BLUETOOTH_A2DP = DEVICE_BLUETOOTH_A2DP,
|
||||||
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
|
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = DEVICE_BLUETOOTH_A2DP_HEADPHONES,
|
||||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
|
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = DEVICE_BLUETOOTH_A2DP_SPEAKER,
|
||||||
DEVICE_OUT_AUX_DIGITAL = 0x400,
|
DEVICE_OUT_AUX_DIGITAL = DEVICE_AUX_DIGITAL,
|
||||||
DEVICE_OUT_DEFAULT = 0x8000,
|
DEVICE_OUT_DEFAULT = 0x8000,
|
||||||
DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
|
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 |
|
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