Merge "Dynamics Processing Effect" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-03-31 00:05:32 +00:00
committed by Android (Google) Code Review

View File

@@ -16,10 +16,11 @@
package android.media.audiofx;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.DynamicsProcessing.Settings;
import android.util.Log;
import java.nio.ByteBuffer;
@@ -90,66 +91,18 @@ public final class DynamicsProcessing extends AudioEffect {
private final static String TAG = "DynamicsProcessing";
/**
* Config object used to initialize and change effect parameters at runtime.
*/
private Config mConfig = null;
// These parameter constants must be synchronized with those in
// /system/media/audio_effects/include/audio_effects/effect_dynamicsprocessing.h
private static final int PARAM_GET_CHANNEL_COUNT = 0x0;
private static final int PARAM_EQ_BAND_COUNT = 0x1;
private static final int PARAM_MBC_BAND_COUNT = 0x2;
private static final int PARAM_INPUT_GAIN = 0x3;
private static final int PARAM_PRE_EQ_ENABLED = 0x10;
private static final int PARAM_PRE_EQ_BAND_ENABLED = 0x11;
private static final int PARAM_PRE_EQ_BAND_FREQUENCY = 0x12;
private static final int PARAM_PRE_EQ_BAND_GAIN = 0x13;
private static final int PARAM_EQ_FREQUENCY_RANGE = 0x22;
private static final int PARAM_EQ_GAIN_RANGE = 0x23;
private static final int PARAM_MBC_ENABLED = 0x30;
private static final int PARAM_MBC_BAND_ENABLED = 0x31;
private static final int PARAM_MBC_BAND_FREQUENCY = 0x32;
private static final int PARAM_MBC_BAND_ATTACK_TIME = 0x33;
private static final int PARAM_MBC_BAND_RELEASE_TIME = 0x34;
private static final int PARAM_MBC_BAND_RATIO = 0x35;
private static final int PARAM_MBC_BAND_THRESHOLD = 0x36;
private static final int PARAM_MBC_BAND_KNEE_WIDTH = 0x37;
private static final int PARAM_MBC_BAND_NOISE_GATE_THRESHOLD = 0x38;
private static final int PARAM_MBC_BAND_EXPANDER_RATIO = 0x39;
private static final int PARAM_MBC_BAND_GAIN_PRE = 0x3A;
private static final int PARAM_MBC_BAND_GAIN_POST = 0x3B;
private static final int PARAM_MBC_FREQUENCY_RANGE = 0x42;
private static final int PARAM_MBC_ATTACK_TIME_RANGE = 0x43;
private static final int PARAM_MBC_RELEASE_TIME_RANGE = 0x44;
private static final int PARAM_MBC_RATIO_RANGE = 0x45;
private static final int PARAM_MBC_THRESHOLD_RANGE = 0x46;
private static final int PARAM_MBC_KNEE_WIDTH_RANGE = 0x47;
private static final int PARAM_MBC_NOISE_GATE_THRESHOLD_RANGE = 0x48;
private static final int PARAM_MBC_EXPANDER_RATIO_RANGE = 0x49;
private static final int PARAM_MBC_GAIN_RANGE = 0x4A;
private static final int PARAM_POST_EQ_ENABLED = 0x50;
private static final int PARAM_POST_EQ_BAND_ENABLED = 0x51;
private static final int PARAM_POST_EQ_BAND_FREQUENCY = 0x52;
private static final int PARAM_POST_EQ_BAND_GAIN = 0x53;
private static final int PARAM_LIMITER_ENABLED = 0x60;
private static final int PARAM_LIMITER_LINK_GROUP = 0x61;
private static final int PARAM_LIMITER_ATTACK_TIME = 0x62;
private static final int PARAM_LIMITER_RELEASE_TIME = 0x63;
private static final int PARAM_LIMITER_RATIO = 0x64;
private static final int PARAM_LIMITER_THRESHOLD = 0x65;
private static final int PARAM_LIMITER_GAIN_POST = 0x66;
private static final int PARAM_LIMITER_ATTACK_TIME_RANGE = 0x72;
private static final int PARAM_LIMITER_RELEASE_TIME_RANGE = 0x73;
private static final int PARAM_LIMITER_RATIO_RANGE = 0x74;
private static final int PARAM_LIMITER_THRESHOLD_RANGE = 0x75;
private static final int PARAM_LIMITER_GAIN_RANGE = 0x76;
private static final int PARAM_VARIANT = 0x100;
private static final int PARAM_VARIANT_DESCRIPTION = 0x101;
private static final int PARAM_VARIANT_COUNT = 0x102;
private static final int PARAM_SET_ENGINE_ARCHITECTURE = 0x200;
private static final int PARAM_GET_CHANNEL_COUNT = 0x10;
private static final int PARAM_INPUT_GAIN = 0x20;
private static final int PARAM_ENGINE_ARCHITECTURE = 0x30;
private static final int PARAM_PRE_EQ = 0x40;
private static final int PARAM_PRE_EQ_BAND = 0x45;
private static final int PARAM_MBC = 0x50;
private static final int PARAM_MBC_BAND = 0x55;
private static final int PARAM_POST_EQ = 0x60;
private static final int PARAM_POST_EQ_BAND = 0x65;
private static final int PARAM_LIMITER = 0x70;
/**
* Index of variant that favors frequency resolution. Frequency domain based implementation.
@@ -226,12 +179,13 @@ public final class DynamicsProcessing extends AudioEffect {
* Config object that suits your needs. A null cfg parameter will create and use a default
* configuration for the effect
*/
public DynamicsProcessing(int priority, int audioSession, Config cfg) {
public DynamicsProcessing(int priority, int audioSession, @Nullable Config cfg) {
super(EFFECT_TYPE_DYNAMICS_PROCESSING, EFFECT_TYPE_NULL, priority, audioSession);
if (audioSession == 0) {
Log.w(TAG, "WARNING: attaching a DynamicsProcessing to global output mix is"
+ "deprecated!");
}
final Config config;
mChannelCount = getChannelCount();
if (cfg == null) {
//create a default configuration and effect, with the number of channels this effect has
@@ -239,21 +193,33 @@ public final class DynamicsProcessing extends AudioEffect {
new DynamicsProcessing.Config.Builder(
CONFIG_DEFAULT_VARIANT,
mChannelCount,
true /*use preEQ*/, 6 /*pre eq bands*/,
true /*use mbc*/, 6 /*mbc bands*/,
true /*use postEQ*/, 6 /*postEq bands*/,
true /*use Limiter*/);
mConfig = builder.build();
CONFIG_DEFAULT_USE_PREEQ,
CONFIG_DEFAULT_PREEQ_BANDS,
CONFIG_DEFAULT_USE_MBC,
CONFIG_DEFAULT_MBC_BANDS,
CONFIG_DEFAULT_USE_POSTEQ,
CONFIG_DEFAULT_POSTEQ_BANDS,
CONFIG_DEFAULT_USE_LIMITER);
config = builder.build();
} else {
//validate channels are ok. decide what to do: replicate channels if more, or fail, or
mConfig = new DynamicsProcessing.Config(mChannelCount, cfg);
//validate channels are ok. decide what to do: replicate channels if more
config = new DynamicsProcessing.Config(mChannelCount, cfg);
}
setEngineArchitecture(mConfig.getVariant(),
mConfig.isPreEqInUse(), mConfig.getPreEqBandCount(),
mConfig.isMbcInUse(), mConfig.getMbcBandCount(),
mConfig.isPostEqInUse(), mConfig.getPostEqBandCount(),
mConfig.isLimiterInUse());
//configure engine
setEngineArchitecture(config.getVariant(),
config.getPreferredFrameDuration(),
config.isPreEqInUse(),
config.getPreEqBandCount(),
config.isMbcInUse(),
config.getMbcBandCount(),
config.isPostEqInUse(),
config.getPostEqBandCount(),
config.isLimiterInUse());
//update all the parameters
for (int ch = 0; ch < mChannelCount; ch++) {
updateEngineChannelByChannelIndex(ch, config.getChannelByChannelIndex(ch));
}
}
/**
@@ -261,11 +227,51 @@ public final class DynamicsProcessing extends AudioEffect {
* @return Config Current Config object used to setup this DynamicsProcessing effect.
*/
public Config getConfig() {
return mConfig;
//Query engine architecture to create config object
Number[] params = { PARAM_ENGINE_ARCHITECTURE };
Number[] values = { 0 /*0 variant */,
0.0f /* 1 preferredFrameDuration */,
0 /*2 preEqInUse */,
0 /*3 preEqBandCount */,
0 /*4 mbcInUse */,
0 /*5 mbcBandCount*/,
0 /*6 postEqInUse */,
0 /*7 postEqBandCount */,
0 /*8 limiterInUse */};
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
getParameter(paramBytes, valueBytes);
byteArrayToNumberArray(valueBytes, values);
DynamicsProcessing.Config.Builder builder =
new DynamicsProcessing.Config.Builder(
values[0].intValue(),
mChannelCount,
values[2].intValue() > 0 /*use preEQ*/,
values[3].intValue() /*pre eq bands*/,
values[4].intValue() > 0 /*use mbc*/,
values[5].intValue() /*mbc bands*/,
values[6].intValue() > 0 /*use postEQ*/,
values[7].intValue()/*postEq bands*/,
values[8].intValue() > 0 /*use Limiter*/).
setPreferredFrameDuration(values[1].floatValue());
Config config = builder.build();
for (int ch = 0; ch < mChannelCount; ch++) {
Channel channel = queryEngineByChannelIndex(ch);
config.setChannelTo(ch, channel);
}
return config;
}
private static final int CONFIG_DEFAULT_VARIANT = 0; //favor frequency
private static final int CONFIG_DEFAULT_VARIANT = VARIANT_FAVOR_FREQUENCY_RESOLUTION;
private static final boolean CONFIG_DEFAULT_USE_PREEQ = true;
private static final int CONFIG_DEFAULT_PREEQ_BANDS = 6;
private static final boolean CONFIG_DEFAULT_USE_MBC = true;
private static final int CONFIG_DEFAULT_MBC_BANDS = 6;
private static final boolean CONFIG_DEFAULT_USE_POSTEQ = true;
private static final int CONFIG_DEFAULT_POSTEQ_BANDS = 6;
private static final boolean CONFIG_DEFAULT_USE_LIMITER = true;
private static final float CHANNEL_DEFAULT_INPUT_GAIN = 0; // dB
private static final float CONFIG_PREFERRED_FRAME_DURATION_MS = 10.0f; //milliseconds
@@ -1276,7 +1282,7 @@ public final class DynamicsProcessing extends AudioEffect {
mChannel = new Channel[mChannelCount];
//check if channelconfig is null or has less channels than channel count.
//options: fill the missing with default options.
// or fail?
// or fail?
for (int ch = 0; ch < mChannelCount; ch++) {
if (ch < channel.length) {
mChannel[ch] = new Channel(channel[ch]); //copy create
@@ -1331,7 +1337,7 @@ public final class DynamicsProcessing extends AudioEffect {
* Class constructor for Config
* @param cfg Configuration object copy constructor
*/
public Config(Config cfg) {
public Config(@NonNull Config cfg) {
this(cfg.mChannelCount, cfg);
}
@@ -1763,138 +1769,115 @@ public final class DynamicsProcessing extends AudioEffect {
}
//=== CHANNEL
public Channel getChannelByChannelIndex(int channelIndex) {
return mConfig.getChannelByChannelIndex(channelIndex);
return queryEngineByChannelIndex(channelIndex);
}
public void setChannelTo(int channelIndex, Channel channel) {
mConfig.setChannelTo(channelIndex, channel);
updateEngineChannelByChannelIndex(channelIndex, channel);
}
public void setAllChannelsTo(Channel channel) {
mConfig.setAllChannelsTo(channel);
for (int ch = 0; ch < mChannelCount; ch++) {
setChannelTo(ch, channel);
}
}
//=== channel params
public float getInputGainByChannelIndex(int channelIndex) {
//TODO: return info from engine instead of cached config
return mConfig.getInputGainByChannelIndex(channelIndex);
return getTwoFloat(PARAM_INPUT_GAIN, channelIndex);
}
public void setInputGainbyChannel(int channelIndex, float inputGain) {
mConfig.setInputGainByChannelIndex(channelIndex, inputGain);
//TODO: communicate change to engine
setTwoFloat(PARAM_INPUT_GAIN, channelIndex, inputGain);
}
public void setInputGainAllChannelsTo(float inputGain) {
mConfig.setInputGainAllChannelsTo(inputGain);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setInputGainbyChannel(ch, inputGain);
}
}
//=== PreEQ
public Eq getPreEqByChannelIndex(int channelIndex) {
//TODO: return info from engine instead of cached config
return mConfig.getPreEqByChannelIndex(channelIndex);
return queryEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex);
}
public void setPreEqByChannelIndex(int channelIndex, Eq preEq) {
mConfig.setPreEqByChannelIndex(channelIndex, preEq);
//TODO: communicate change to engine
updateEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex, preEq);
}
public void setPreEqAllChannelsTo(Eq preEq) {
mConfig.setPreEqAllChannelsTo(preEq);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setPreEqByChannelIndex(ch, preEq);
}
}
public EqBand getPreEqBandByChannelIndex(int channelIndex, int band) {
//TODO: return info from engine instead of cached config
return mConfig.getPreEqBandByChannelIndex(channelIndex, band);
return queryEngineEqBandByChannelIndex(PARAM_PRE_EQ_BAND, channelIndex, band);
}
public void setPreEqBandByChannelIndex(int channelIndex, int band, EqBand preEqBand) {
mConfig.setPreEqBandByChannelIndex(channelIndex, band, preEqBand);
//TODO: communicate change to engine
updateEngineEqBandByChannelIndex(PARAM_PRE_EQ_BAND, channelIndex, band, preEqBand);
}
public void setPreEqBandAllChannelsTo(int band, EqBand preEqBand) {
mConfig.setPreEqBandAllChannelsTo(band, preEqBand);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setPreEqBandByChannelIndex(ch, band, preEqBand);
}
}
//=== MBC
public Mbc getMbcByChannelIndex(int channelIndex) {
//TODO: return info from engine instead of cached config
return mConfig.getMbcByChannelIndex(channelIndex);
return queryEngineMbcByChannelIndex(channelIndex);
}
public void setMbcByChannelIndex(int channelIndex, Mbc mbc) {
mConfig.setMbcByChannelIndex(channelIndex, mbc);
//TODO: communicate change to engine
updateEngineMbcByChannelIndex(channelIndex, mbc);
}
public void setMbcAllChannelsTo(Mbc mbc) {
mConfig.setMbcAllChannelsTo(mbc);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setMbcByChannelIndex(ch, mbc);
}
}
public MbcBand getMbcBandByChannelIndex(int channelIndex, int band) {
//TODO: return info from engine instead of cached config
return mConfig.getMbcBandByChannelIndex(channelIndex, band);
return queryEngineMbcBandByChannelIndex(channelIndex, band);
}
public void setMbcBandByChannelIndex(int channelIndex, int band, MbcBand mbcBand) {
mConfig.setMbcBandByChannelIndex(channelIndex, band, mbcBand);
//TODO: communicate change to engine
updateEngineMbcBandByChannelIndex(channelIndex, band, mbcBand);
}
public void setMbcBandAllChannelsTo(int band, MbcBand mbcBand) {
mConfig.setMbcBandAllChannelsTo(band, mbcBand);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setMbcBandByChannelIndex(ch, band, mbcBand);
}
}
//== PostEq
public Eq getPostEqByChannelIndex(int channelIndex) {
//TODO: return info from engine instead of cached config
return mConfig.getPostEqByChannelIndex(channelIndex);
return queryEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex);
}
public void setPostEqByChannelIndex(int channelIndex, Eq postEq) {
mConfig.setPostEqByChannelIndex(channelIndex, postEq);
//TODO: communicate change to engine
updateEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex, postEq);
}
public void setPostEqAllChannelsTo(Eq postEq) {
mConfig.setPostEqAllChannelsTo(postEq);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setPostEqByChannelIndex(ch, postEq);
}
}
public EqBand getPostEqBandByChannelIndex(int channelIndex, int band) {
//TODO: return info from engine instead of cached config
return mConfig.getPostEqBandByChannelIndex(channelIndex, band);
return queryEngineEqBandByChannelIndex(PARAM_POST_EQ_BAND, channelIndex, band);
}
public void setPostEqBandByChannelIndex(int channelIndex, int band, EqBand postEqBand) {
mConfig.setPostEqBandByChannelIndex(channelIndex, band, postEqBand);
//TODO: communicate change to engine
updateEngineEqBandByChannelIndex(PARAM_POST_EQ_BAND, channelIndex, band, postEqBand);
}
public void setPostEqBandAllChannelsTo(int band, EqBand postEqBand) {
mConfig.setPostEqBandAllChannelsTo(band, postEqBand);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setPostEqBandByChannelIndex(ch, band, postEqBand);
}
}
//==== Limiter
public Limiter getLimiterByChannelIndex(int channelIndex) {
//TODO: return info from engine instead of cached config
return mConfig.getLimiterByChannelIndex(channelIndex);
return queryEngineLimiterByChannelIndex(channelIndex);
}
public void setLimiterByChannelIndex(int channelIndex, Limiter limiter) {
mConfig.setLimiterByChannelIndex(channelIndex, limiter);
//TODO: communicate change to engine
updateEngineLimiterByChannelIndex(channelIndex, limiter);
}
public void setLimiterAllChannelsTo(Limiter limiter) {
mConfig.setLimiterAllChannelsTo(limiter);
//TODO: communicate change to engine
for (int ch = 0; ch < mChannelCount; ch++) {
setLimiterByChannelIndex(ch, limiter);
}
}
/**
@@ -1905,165 +1888,327 @@ public final class DynamicsProcessing extends AudioEffect {
return getOneInt(PARAM_GET_CHANNEL_COUNT);
}
private void setEngineArchitecture(int variant, boolean preEqInUse, int preEqBandCount,
boolean mbcInUse, int mbcBandCount, boolean postEqInUse, int postEqBandCount,
boolean limiterInUse) {
int[] values = { variant, (preEqInUse ? 1 : 0), preEqBandCount,
(mbcInUse ? 1 : 0), mbcBandCount, (postEqInUse ? 1 : 0), postEqBandCount,
//=== Engine calls
private void setEngineArchitecture(int variant, float preferredFrameDuration,
boolean preEqInUse, int preEqBandCount, boolean mbcInUse, int mbcBandCount,
boolean postEqInUse, int postEqBandCount, boolean limiterInUse) {
Number[] params = { PARAM_ENGINE_ARCHITECTURE };
Number[] values = { variant /* variant */,
preferredFrameDuration,
(preEqInUse ? 1 : 0),
preEqBandCount,
(mbcInUse ? 1 : 0),
mbcBandCount,
(postEqInUse ? 1 : 0),
postEqBandCount,
(limiterInUse ? 1 : 0)};
//TODO: enable later setIntArray(PARAM_SET_ENGINE_ARCHITECTURE, values);
setNumberArray(params, values);
}
private void updateEngineEqBandByChannelIndex(int param, int channelIndex, int bandIndex,
@NonNull EqBand eqBand) {
Number[] params = {param,
channelIndex,
bandIndex};
Number[] values = {(eqBand.isEnabled() ? 1 : 0),
eqBand.getCutoffFrequency(),
eqBand.getGain()};
setNumberArray(params, values);
}
private Eq queryEngineEqByChannelIndex(int param, int channelIndex) {
Number[] params = {param == PARAM_PRE_EQ ? PARAM_PRE_EQ : PARAM_POST_EQ,
channelIndex};
Number[] values = {0 /*0 in use */,
0 /*1 enabled*/,
0 /*2 band count */};
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
getParameter(paramBytes, valueBytes);
byteArrayToNumberArray(valueBytes, values);
int bandCount = values[2].intValue();
Eq eq = new Eq(values[0].intValue() > 0 /* in use */,
values[1].intValue() > 0 /* enabled */,
bandCount /*band count*/);
for (int b = 0; b < bandCount; b++) {
EqBand eqBand = queryEngineEqBandByChannelIndex(param == PARAM_PRE_EQ ?
PARAM_PRE_EQ_BAND : PARAM_POST_EQ_BAND, channelIndex, b);
eq.setBand(b, eqBand);
}
return eq;
}
private EqBand queryEngineEqBandByChannelIndex(int param, int channelIndex, int bandIndex) {
Number[] params = {param,
channelIndex,
bandIndex};
Number[] values = {0 /*0 enabled*/,
0.0f /*1 cutoffFrequency */,
0.0f /*2 gain */};
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
getParameter(paramBytes, valueBytes);
byteArrayToNumberArray(valueBytes, values);
return new EqBand(values[0].intValue() > 0 /* enabled */,
values[1].floatValue() /* cutoffFrequency */,
values[2].floatValue() /* gain*/);
}
private void updateEngineEqByChannelIndex(int param, int channelIndex, @NonNull Eq eq) {
int bandCount = eq.getBandCount();
Number[] params = {param,
channelIndex};
Number[] values = { (eq.isInUse() ? 1 : 0),
(eq.isEnabled() ? 1 : 0),
bandCount};
setNumberArray(params, values);
for (int b = 0; b < bandCount; b++) {
EqBand eqBand = eq.getBand(b);
updateEngineEqBandByChannelIndex(param == PARAM_PRE_EQ ?
PARAM_PRE_EQ_BAND : PARAM_POST_EQ_BAND, channelIndex, b, eqBand);
}
}
private Mbc queryEngineMbcByChannelIndex(int channelIndex) {
Number[] params = {PARAM_MBC,
channelIndex};
Number[] values = {0 /*0 in use */,
0 /*1 enabled*/,
0 /*2 band count */};
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
getParameter(paramBytes, valueBytes);
byteArrayToNumberArray(valueBytes, values);
int bandCount = values[2].intValue();
Mbc mbc = new Mbc(values[0].intValue() > 0 /* in use */,
values[1].intValue() > 0 /* enabled */,
bandCount /*band count*/);
for (int b = 0; b < bandCount; b++) {
MbcBand mbcBand = queryEngineMbcBandByChannelIndex(channelIndex, b);
mbc.setBand(b, mbcBand);
}
return mbc;
}
private MbcBand queryEngineMbcBandByChannelIndex(int channelIndex, int bandIndex) {
Number[] params = {PARAM_MBC_BAND,
channelIndex,
bandIndex};
Number[] values = {0 /*0 enabled */,
0.0f /*1 cutoffFrequency */,
0.0f /*2 AttackTime */,
0.0f /*3 ReleaseTime */,
0.0f /*4 Ratio */,
0.0f /*5 Threshold */,
0.0f /*6 KneeWidth */,
0.0f /*7 NoiseGateThreshold */,
0.0f /*8 ExpanderRatio */,
0.0f /*9 PreGain */,
0.0f /*10 PostGain*/};
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
getParameter(paramBytes, valueBytes);
byteArrayToNumberArray(valueBytes, values);
return new MbcBand(values[0].intValue() > 0 /* enabled */,
values[1].floatValue() /* cutoffFrequency */,
values[2].floatValue()/*2 AttackTime */,
values[3].floatValue()/*3 ReleaseTime */,
values[4].floatValue()/*4 Ratio */,
values[5].floatValue()/*5 Threshold */,
values[6].floatValue()/*6 KneeWidth */,
values[7].floatValue()/*7 NoiseGateThreshold */,
values[8].floatValue()/*8 ExpanderRatio */,
values[9].floatValue()/*9 PreGain */,
values[10].floatValue()/*10 PostGain*/);
}
private void updateEngineMbcBandByChannelIndex(int channelIndex, int bandIndex,
@NonNull MbcBand mbcBand) {
Number[] params = { PARAM_MBC_BAND,
channelIndex,
bandIndex};
Number[] values = {(mbcBand.isEnabled() ? 1 : 0),
mbcBand.getCutoffFrequency(),
mbcBand.getAttackTime(),
mbcBand.getReleaseTime(),
mbcBand.getRatio(),
mbcBand.getThreshold(),
mbcBand.getKneeWidth(),
mbcBand.getNoiseGateThreshold(),
mbcBand.getExpanderRatio(),
mbcBand.getPreGain(),
mbcBand.getPostGain()};
setNumberArray(params, values);
}
private void updateEngineMbcByChannelIndex(int channelIndex, @NonNull Mbc mbc) {
int bandCount = mbc.getBandCount();
Number[] params = { PARAM_MBC,
channelIndex};
Number[] values = {(mbc.isInUse() ? 1 : 0),
(mbc.isEnabled() ? 1 : 0),
bandCount};
setNumberArray(params, values);
for (int b = 0; b < bandCount; b++) {
MbcBand mbcBand = mbc.getBand(b);
updateEngineMbcBandByChannelIndex(channelIndex, b, mbcBand);
}
}
private void updateEngineLimiterByChannelIndex(int channelIndex, @NonNull Limiter limiter) {
Number[] params = { PARAM_LIMITER,
channelIndex};
Number[] values = {(limiter.isInUse() ? 1 : 0),
(limiter.isEnabled() ? 1 : 0),
limiter.getLinkGroup(),
limiter.getAttackTime(),
limiter.getReleaseTime(),
limiter.getRatio(),
limiter.getThreshold(),
limiter.getPostGain()};
setNumberArray(params, values);
}
private Limiter queryEngineLimiterByChannelIndex(int channelIndex) {
Number[] params = {PARAM_LIMITER,
channelIndex};
Number[] values = {0 /*0 in use (int)*/,
0 /*1 enabled (int)*/,
0 /*2 link group (int)*/,
0.0f /*3 attack time (float)*/,
0.0f /*4 release time (float)*/,
0.0f /*5 ratio (float)*/,
0.0f /*6 threshold (float)*/,
0.0f /*7 post gain(float)*/};
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values); //just interest in the byte size.
getParameter(paramBytes, valueBytes);
byteArrayToNumberArray(valueBytes, values);
return new Limiter(values[0].intValue() > 0 /*in use*/,
values[1].intValue() > 0 /*enabled*/,
values[2].intValue() /*linkGroup*/,
values[3].floatValue() /*attackTime*/,
values[4].floatValue() /*releaseTime*/,
values[5].floatValue() /*ratio*/,
values[6].floatValue() /*threshold*/,
values[7].floatValue() /*postGain*/);
}
private Channel queryEngineByChannelIndex(int channelIndex) {
float inputGain = getTwoFloat(PARAM_INPUT_GAIN, channelIndex);
Eq preEq = queryEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex);
Mbc mbc = queryEngineMbcByChannelIndex(channelIndex);
Eq postEq = queryEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex);
Limiter limiter = queryEngineLimiterByChannelIndex(channelIndex);
Channel channel = new Channel(inputGain,
preEq.isInUse(), preEq.getBandCount(),
mbc.isInUse(), mbc.getBandCount(),
postEq.isInUse(), postEq.getBandCount(),
limiter.isInUse());
channel.setInputGain(inputGain);
channel.setPreEq(preEq);
channel.setMbc(mbc);
channel.setPostEq(postEq);
channel.setLimiter(limiter);
return channel;
}
private void updateEngineChannelByChannelIndex(int channelIndex, @NonNull Channel channel) {
//send things with as few calls as possible
setTwoFloat(PARAM_INPUT_GAIN, channelIndex, channel.getInputGain());
Eq preEq = channel.getPreEq();
updateEngineEqByChannelIndex(PARAM_PRE_EQ, channelIndex, preEq);
Mbc mbc = channel.getMbc();
updateEngineMbcByChannelIndex(channelIndex, mbc);
Eq postEq = channel.getPostEq();
updateEngineEqByChannelIndex(PARAM_POST_EQ, channelIndex, postEq);
Limiter limiter = channel.getLimiter();
updateEngineLimiterByChannelIndex(channelIndex, limiter);
}
//****** convenience methods:
//
private int getOneInt(int paramGet) {
int[] param = new int[1];
int[] result = new int[1];
private int getOneInt(int param) {
final int[] params = { param };
final int[] result = new int[1];
param[0] = paramGet;
checkStatus(getParameter(param, result));
checkStatus(getParameter(params, result));
return result[0];
}
private int getTwoInt(int paramGet, int paramA) {
int[] param = new int[2];
int[] result = new int[1];
private void setTwoFloat(int param, int paramA, float valueSet) {
final int[] params = { param, paramA };
final byte[] value;
param[0] = paramGet;
param[1] = paramA;
checkStatus(getParameter(param, result));
return result[0];
}
private int getThreeInt(int paramGet, int paramA, int paramB) {
//have to use bytearrays, with more than 2 parameters.
byte[] paramBytes = concatArrays(intToByteArray(paramGet),
intToByteArray(paramA),
intToByteArray(paramB));
byte[] resultBytes = new byte[4]; //single int
checkStatus(getParameter(paramBytes, resultBytes));
return byteArrayToInt(resultBytes);
}
private void setOneInt(int paramSet, int valueSet) {
int[] param = new int[1];
int[] value = new int[1];
param[0] = paramSet;
value[0] = valueSet;
checkStatus(setParameter(param, value));
}
private void setTwoInt(int paramSet, int paramA, int valueSet) {
int[] param = new int[2];
int[] value = new int[1];
param[0] = paramSet;
param[1] = paramA;
value[0] = valueSet;
checkStatus(setParameter(param, value));
}
private void setThreeInt(int paramSet, int paramA, int paramB, int valueSet) {
//have to use bytearrays, with more than 2 parameters.
byte[] paramBytes = concatArrays(intToByteArray(paramSet),
intToByteArray(paramA),
intToByteArray(paramB));
byte[] valueBytes = intToByteArray(valueSet);
checkStatus(setParameter(paramBytes, valueBytes));
}
private void setOneFloat(int paramSet, float valueSet) {
int[] param = new int[1];
byte[] value;
param[0] = paramSet;
value = floatToByteArray(valueSet);
checkStatus(setParameter(param, value));
checkStatus(setParameter(params, value));
}
private void setTwoFloat(int paramSet, int paramA, float valueSet) {
int[] param = new int[2];
byte[] value;
param[0] = paramSet;
param[1] = paramA;
value = floatToByteArray(valueSet);
checkStatus(setParameter(param, value));
}
private void setThreeFloat(int paramSet, int paramA, int paramB, float valueSet) {
//have to use bytearrays, with more than 2 parameters.
byte[] paramBytes = concatArrays(intToByteArray(paramSet),
intToByteArray(paramA),
intToByteArray(paramB));
byte[] valueBytes = floatToByteArray(valueSet);
checkStatus(setParameter(paramBytes, valueBytes));
}
private byte[] intArrayToByteArray(int[] values) {
int expectedBytes = values.length * 4;
private byte[] numberArrayToByteArray(Number[] values) {
int expectedBytes = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof Integer) {
expectedBytes += Integer.BYTES;
} else if (values[i] instanceof Float) {
expectedBytes += Float.BYTES;
} else {
throw new IllegalArgumentException("unknown value type " +
values[i].getClass());
}
}
ByteBuffer converter = ByteBuffer.allocate(expectedBytes);
converter.order(ByteOrder.nativeOrder());
for (int k = 0; k < values.length; k++) {
converter.putFloat(values[k]);
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof Integer) {
converter.putInt(values[i].intValue());
} else if (values[i] instanceof Float) {
converter.putFloat(values[i].floatValue());
}
}
return converter.array();
}
private void setIntArray(int paramSet, int[] paramArray) {
//have to use bytearrays, with more than 2 parameters.
byte[] paramBytes = intToByteArray(paramSet);
byte[] valueBytes = intArrayToByteArray(paramArray);
private void byteArrayToNumberArray(byte[] valuesIn, Number[] valuesOut) {
int inIndex = 0;
int outIndex = 0;
while (inIndex < valuesIn.length && outIndex < valuesOut.length) {
if (valuesOut[outIndex] instanceof Integer) {
valuesOut[outIndex++] = byteArrayToInt(valuesIn, inIndex);
inIndex += Integer.BYTES;
} else if (valuesOut[outIndex] instanceof Float) {
valuesOut[outIndex++] = byteArrayToFloat(valuesIn, inIndex);
inIndex += Float.BYTES;
} else {
throw new IllegalArgumentException("can't convert " +
valuesOut[outIndex].getClass());
}
}
if (outIndex != valuesOut.length) {
throw new IllegalArgumentException("only converted " + outIndex +
" values out of "+ valuesOut.length + " expected");
}
}
private void setNumberArray(Number[] params, Number[] values) {
byte[] paramBytes = numberArrayToByteArray(params);
byte[] valueBytes = numberArrayToByteArray(values);
checkStatus(setParameter(paramBytes, valueBytes));
}
private float getOneFloat(int paramGet) {
int[] param = new int[1];
byte[] result = new byte[4];
private float getTwoFloat(int param, int paramA) {
final int[] params = { param, paramA };
final byte[] result = new byte[4];
param[0] = paramGet;
checkStatus(getParameter(param, result));
checkStatus(getParameter(params, result));
return byteArrayToFloat(result);
}
private float getTwoFloat(int paramGet, int paramA) {
int[] param = new int[2];
byte[] result = new byte[4];
param[0] = paramGet;
param[1] = paramA;
checkStatus(getParameter(param, result));
return byteArrayToFloat(result);
}
private float getThreeFloat(int paramGet, int paramA, int paramB) {
//have to use bytearrays, with more than 2 parameters.
byte[] paramBytes = concatArrays(intToByteArray(paramGet),
intToByteArray(paramA),
intToByteArray(paramB));
byte[] resultBytes = new byte[4]; //single float
checkStatus(getParameter(paramBytes, resultBytes));
return byteArrayToFloat(resultBytes);
}
private float[] getOneFloatArray(int paramGet, int expectedSize) {
int[] param = new int[1];
byte[] result = new byte[4 * expectedSize];
param[0] = paramGet;
checkStatus(getParameter(param, result));
float[] returnArray = new float[expectedSize];
for (int k = 0; k < expectedSize; k++) {
returnArray[k] = byteArrayToFloat(result, 4 * k);
}
return returnArray;
}
/**
* @hide
* The OnParameterChangeListener interface defines a method called by the DynamicsProcessing