summaryrefslogtreecommitdiffstats
path: root/src/org/cyanogenmod/audiofx/backends
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/cyanogenmod/audiofx/backends')
-rw-r--r--src/org/cyanogenmod/audiofx/backends/AndroidEffects.java200
-rw-r--r--src/org/cyanogenmod/audiofx/backends/EffectSet.java250
-rw-r--r--src/org/cyanogenmod/audiofx/backends/EffectSetWithAndroidEq.java135
-rw-r--r--src/org/cyanogenmod/audiofx/backends/IEffectFactory.java31
4 files changed, 616 insertions, 0 deletions
diff --git a/src/org/cyanogenmod/audiofx/backends/AndroidEffects.java b/src/org/cyanogenmod/audiofx/backends/AndroidEffects.java
new file mode 100644
index 0000000..fafcd34
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/backends/AndroidEffects.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod 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.
+ */
+package org.cyanogenmod.audiofx.backends;
+
+import android.media.AudioDeviceInfo;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.BassBoost;
+import android.media.audiofx.PresetReverb;
+import android.media.audiofx.Virtualizer;
+import android.util.Log;
+
+import org.cyanogenmod.audiofx.Constants;
+
+/**
+ * EffectSet which comprises standard Android effects
+ */
+class AndroidEffects extends EffectSetWithAndroidEq {
+
+ /**
+ * Session-specific bassboost
+ */
+ private BassBoost mBassBoost;
+
+ /**
+ * Session-specific virtualizer
+ */
+ private Virtualizer mVirtualizer;
+
+ /**
+ * Session-specific reverb
+ */
+ private PresetReverb mPresetReverb;
+
+ public AndroidEffects(int sessionId, AudioDeviceInfo deviceInfo) {
+ super(sessionId, deviceInfo);
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+
+ mBassBoost = new BassBoost(100, mSessionId);
+ mVirtualizer = new Virtualizer(100, mSessionId);
+ mPresetReverb = new PresetReverb(100, mSessionId);
+ }
+
+ @Override
+ public void release() {
+ super.release();
+
+ try {
+ if (mBassBoost != null) {
+ mBassBoost.release();
+ }
+ } catch (Exception e) {
+ // ignored;
+ }
+ try {
+ if (mVirtualizer != null) {
+ mVirtualizer.release();
+ }
+ } catch (Exception e) {
+ // ignored
+ }
+ try {
+ if (mPresetReverb != null) {
+ mPresetReverb.release();
+ }
+ } catch (Exception e) {
+ // ignored
+ }
+ mBassBoost = null;
+ mVirtualizer = null;
+ mPresetReverb = null;
+ }
+
+ @Override
+ public synchronized void setDevice(AudioDeviceInfo deviceInfo) {
+ super.setDevice(deviceInfo);
+ }
+
+ @Override
+ public void setGlobalEnabled(boolean globalEnabled) {
+ super.setGlobalEnabled(globalEnabled);
+
+ if (!globalEnabled) {
+ // disable everything. it will get explictly enabled
+ // individually when necessary.
+ try {
+ if (mVirtualizer != null) {
+ mVirtualizer.setEnabled(false);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to disable virtualizer!", e);
+ }
+ try {
+ if (mBassBoost != null) {
+ mBassBoost.setEnabled(false);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to disable bass boost!", e);
+ }
+ try {
+ if (mPresetReverb != null) {
+ mPresetReverb.setEnabled(false);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to disable reverb!", e);
+ }
+ }
+ }
+
+ @Override
+ public boolean hasVirtualizer() {
+ return mVirtualizer != null && mVirtualizer.getStrengthSupported();
+ }
+
+ @Override
+ public boolean hasBassBoost() {
+ return mBassBoost != null && mBassBoost.getStrengthSupported();
+ }
+
+ @Override
+ public void enableBassBoost(boolean enable) {
+ try {
+ if (mBassBoost != null) {
+ mBassBoost.setEnabled(enable);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " bass boost!", e);
+ }
+ }
+
+ @Override
+ public void setBassBoostStrength(short strength) {
+ setParameterSafe(mBassBoost, BassBoost.PARAM_STRENGTH, strength);
+ }
+
+ @Override
+ public void enableVirtualizer(boolean enable) {
+ try {
+ if (mVirtualizer != null) {
+ mVirtualizer.setEnabled(enable);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " virtualizer!", e);
+ }
+ }
+
+ @Override
+ public void setVirtualizerStrength(short strength) {
+ setParameterSafe(mVirtualizer, Virtualizer.PARAM_STRENGTH, strength);
+ }
+
+ @Override
+ public void enableReverb(boolean enable) {
+ try {
+ if (mPresetReverb != null) {
+ mPresetReverb.setEnabled(enable);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " preset reverb!", e);
+ }
+
+ }
+
+ @Override
+ public void setReverbPreset(short preset) {
+ setParameterSafe(mPresetReverb, PresetReverb.PARAM_PRESET, preset);
+ }
+
+ @Override
+ public int getBrand() {
+ return Constants.EFFECT_TYPE_ANDROID;
+ }
+
+ private void setParameterSafe(AudioEffect e, int p, short v) {
+ if (e == null) {
+ return;
+ }
+ try {
+ e.setParameter(p, v);
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to set param " + p + " for effect " + e.getDescriptor().name, ex);
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/backends/EffectSet.java b/src/org/cyanogenmod/audiofx/backends/EffectSet.java
new file mode 100644
index 0000000..2d336b9
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/backends/EffectSet.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod 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.
+ */
+package org.cyanogenmod.audiofx.backends;
+
+import android.media.AudioDeviceInfo;
+import android.util.Log;
+
+/**
+ * Helper class representing the full complement of effects attached to one
+ * audio session.
+ */
+public abstract class EffectSet {
+
+ protected static final String TAG = "AudioFx-EffectSet";
+
+ protected final int mSessionId;
+
+ protected boolean mGlobalEnabled;
+
+ private AudioDeviceInfo mDeviceInfo;
+
+ private boolean mMarkedForDeath = false;
+
+ public EffectSet(int sessionId, AudioDeviceInfo deviceInfo) {
+ mSessionId = sessionId;
+ mDeviceInfo = deviceInfo;
+ try {
+ onCreate();
+ } catch (Exception e) {
+ Log.e(TAG, "error creating" + this + ", releasing and throwing!");
+ release();
+ throw e;
+ }
+ }
+
+ /**
+ * Called to do subclass-first initialization in case
+ * an implementation has ordering restrictions.
+ *
+ * This call is wrapped in a try/catch - if an exception is thrown here,
+ * a release will immediately be called.
+ */
+ protected void onCreate() { }
+
+ /**
+ * Destroy all effects in this set.
+ *
+ * Attempting to use this object after calling release is
+ * undefined behavior.
+ */
+ public void release() { }
+
+ /**
+ * Returns the enumerated brand of this implementation
+ * @return brandId
+ */
+ public abstract int getBrand();
+
+ /**
+ * Called when the user toggles the engine on or off. If the
+ * implementation has a built-in bypass mode, this is where
+ * to use it.
+ *
+ * @param globalEnabled
+ */
+ public void setGlobalEnabled(boolean globalEnabled) {
+ mGlobalEnabled = globalEnabled;
+ }
+
+ public boolean isGlobalEnabled() {
+ return mGlobalEnabled;
+ }
+
+ /**
+ * Called when the output device has changed. All cached
+ * data should be cleared at this point.
+ *
+ * @param deviceInfo
+ */
+ public void setDevice(AudioDeviceInfo deviceInfo) {
+ mDeviceInfo = deviceInfo;
+ }
+
+ /**
+ * Return the current active output device
+ * @return deviceInfo
+ */
+ public AudioDeviceInfo getDevice() {
+ return mDeviceInfo;
+ }
+
+ /**
+ * Begin bulk-update of parameters. This can be used if the
+ * implementation supports operation in a transactional/atomic
+ * manner. Parameter changes will immediately follow this call
+ * and should be committed to the backend when the subsequent
+ * commitUpdate() is called.
+ *
+ * Optional.
+ *
+ * @return status - false on failure
+ */
+ public boolean beginUpdate() { return true; }
+
+ /**
+ * Commit accumulated updates to the backend. See above.
+ *
+ * begin/commit are used when a large number of parameters need
+ * to be sent to the backend, such as in the case of a device
+ * switch or preset change. This can increase performance and
+ * reduce click/pop issues.
+ *
+ * Optional.
+ *
+ * @return status - false on failure
+ */
+ public boolean commitUpdate() { return true; }
+
+ /* ---- Top level effects begin here ---- */
+
+ // required effects
+ public abstract boolean hasVirtualizer();
+
+ public abstract boolean hasBassBoost();
+
+ // optional effects
+ public boolean hasTrebleBoost() {
+ return false;
+ }
+
+ public boolean hasVolumeBoost() {
+ return false;
+ }
+
+ public boolean hasReverb() {
+ return false;
+ }
+
+ public abstract void enableEqualizer(boolean enable);
+
+ /**
+ * @param levels in decibels
+ */
+ public abstract void setEqualizerLevelsDecibels(float[] levels);
+
+ public abstract short getNumEqualizerBands();
+
+ /**
+ * @param band
+ * @param level in millibels
+ */
+ public abstract void setEqualizerBandLevel(short band, float level);
+
+ /**
+ * @return level in millibels
+ */
+ public abstract int getEqualizerBandLevel(short band);
+
+ public abstract String getEqualizerPresetName(short preset);
+
+ public abstract void useEqualizerPreset(short preset);
+
+ public abstract short getNumEqualizerPresets();
+
+ public abstract short[] getEqualizerBandLevelRange();
+
+ /**
+ * @param band
+ * @return center frequency of the band in millihertz
+ */
+ public abstract int getCenterFrequency(short band);
+
+ public abstract void enableBassBoost(boolean enable);
+
+ /**
+ * @param strength with range [0-1000]
+ */
+ public abstract void setBassBoostStrength(short strength);
+
+ public abstract void enableVirtualizer(boolean enable);
+
+ /**
+ * @param strength with range [0-1000]
+ */
+ public abstract void setVirtualizerStrength(short strength);
+
+ public void enableReverb(boolean enable) {
+ return;
+ }
+
+ public void setReverbPreset(short preset) {
+ return;
+ }
+
+ public void enableTrebleBoost(boolean enable) {
+ return;
+ }
+
+ /**
+ * @param strength with range [0-100]
+ */
+ public void setTrebleBoostStrength(short strength) {
+ return;
+ }
+
+ public void enableVolumeBoost(boolean enable) {
+ return;
+ }
+
+ /**
+ * How long should we delay for when releasing the effects?
+ * This helps certain effect implementations when the
+ * app is reusing a session ID. By default this
+ * behavior is disabled.
+ */
+ public int getReleaseDelay() {
+ return 0;
+ }
+
+ public boolean isMarkedForDeath() {
+ return mMarkedForDeath;
+ }
+
+ public void setMarkedForDeath(boolean die) {
+ mMarkedForDeath = die;
+ }
+
+ @Override
+ public String toString() {
+ return "EffectSet (" + this.getClass().getSimpleName() + ")"
+ + " [ "
+ + " mSessionId: " + mSessionId
+ + " mDeviceInfo: " + mDeviceInfo
+ + " mGlobalEnabled: " + mGlobalEnabled
+ + " ]";
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/backends/EffectSetWithAndroidEq.java b/src/org/cyanogenmod/audiofx/backends/EffectSetWithAndroidEq.java
new file mode 100644
index 0000000..42d1cca
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/backends/EffectSetWithAndroidEq.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod 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.
+ */
+package org.cyanogenmod.audiofx.backends;
+
+import android.media.AudioDeviceInfo;
+import android.media.audiofx.Equalizer;
+import android.util.Log;
+
+import org.cyanogenmod.audiofx.eq.EqUtils;
+
+public abstract class EffectSetWithAndroidEq extends EffectSet {
+ /**
+ * Session-specific equalizer
+ */
+ private Equalizer mEqualizer;
+
+ private short mEqNumPresets = -1;
+ private short mEqNumBands = -1;
+
+ public EffectSetWithAndroidEq(int sessionId, AudioDeviceInfo deviceInfo) {
+ super(sessionId, deviceInfo);
+ }
+
+ @Override
+ protected void onCreate() {
+ mEqualizer = new Equalizer(100, mSessionId);
+ super.onCreate();
+
+ }
+
+ @Override
+ public synchronized void release() {
+ if (mEqualizer != null) {
+ mEqualizer.release();
+ mEqualizer = null;
+ }
+ super.release();
+ }
+
+ @Override
+ public void setGlobalEnabled(boolean globalEnabled) {
+ super.setGlobalEnabled(globalEnabled);
+
+ enableEqualizer(globalEnabled);
+ }
+
+ @Override
+ public void enableEqualizer(boolean enable) {
+ try {
+ mEqualizer.setEnabled(enable);
+ } catch (Exception e) {
+ Log.e(TAG, "enableEqualizer failed! enable=" + enable + " sessionId=" + mSessionId, e);
+ }
+ }
+
+ @Override
+ public void setEqualizerLevelsDecibels(float[] levels) {
+ final short[] equalizerLevels = EqUtils.convertDecibelsToMillibelsInShorts(levels);
+ for (short i = 0; i < equalizerLevels.length; i++) {
+ setBandLevelSafe(i, equalizerLevels[i]);
+ }
+ }
+
+ @Override
+ public short getNumEqualizerBands() {
+ if (mEqNumBands < 0) {
+ mEqNumBands = mEqualizer.getNumberOfBands();
+ }
+ return mEqNumBands;
+ }
+
+ @Override
+ public void setEqualizerBandLevel(short band, float level) {
+ setBandLevelSafe(band, (short)level);
+ }
+
+ @Override
+ public int getEqualizerBandLevel(short band) {
+ return mEqualizer.getBandLevel(band);
+ }
+
+ @Override
+ public String getEqualizerPresetName(short preset) {
+ return mEqualizer.getPresetName(preset);
+ }
+
+ @Override
+ public void useEqualizerPreset(short preset) {
+ mEqualizer.usePreset(preset);
+ }
+
+ @Override
+ public short getNumEqualizerPresets() {
+ if (mEqNumPresets < 0) {
+ mEqNumPresets = mEqualizer.getNumberOfPresets();
+ }
+ return mEqNumPresets;
+ }
+
+ @Override
+ public short[] getEqualizerBandLevelRange() {
+ return mEqualizer.getBandLevelRange();
+ }
+
+ @Override
+ public int getCenterFrequency(short band) {
+ return mEqualizer.getCenterFreq(band);
+ }
+
+ @Override
+ public synchronized void setDevice(AudioDeviceInfo deviceInfo) {
+ super.setDevice(deviceInfo);
+ }
+
+ private synchronized void setBandLevelSafe(short band, short level) {
+ try {
+ mEqualizer.setBandLevel(band, level);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to set eq band=" + band + " level=" + level, e);
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/backends/IEffectFactory.java b/src/org/cyanogenmod/audiofx/backends/IEffectFactory.java
new file mode 100644
index 0000000..c427dee
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/backends/IEffectFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod 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.
+ */
+package org.cyanogenmod.audiofx.backends;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+
+interface IEffectFactory {
+
+ /**
+ * Create a new EffectSet based on current stream parameters.
+ * @param context context to create the effect with
+ * @param sessionId session id to attach the effect to
+ * @param currentDevice current device that the effect should initially setup for
+ * @return an {@link EffectSet}
+ */
+ EffectSet createEffectSet(Context context, int sessionId, AudioDeviceInfo currentDevice);
+}