diff options
Diffstat (limited to 'src/org/cyanogenmod/audiofx/backends')
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); +} |