diff --git a/dolby/res/values/strings.xml b/dolby/res/values/strings.xml index c71a4b0..d7a3520 100644 --- a/dolby/res/values/strings.xml +++ b/dolby/res/values/strings.xml @@ -21,7 +21,8 @@ Settings Bass enhancer Dialogue enhancer - Surround virtualizer + Speaker virtualization + Headphone virtualization Stereo widening Volume leveler Connect headphones diff --git a/dolby/res/xml/dolby_settings.xml b/dolby/res/xml/dolby_settings.xml index e7d4743..fcee75f 100644 --- a/dolby/res/xml/dolby_settings.xml +++ b/dolby/res/xml/dolby_settings.xml @@ -30,15 +30,18 @@ android:entryValues="@array/dolby_preset_values" android:title="@string/dolby_preset" /> + + + android:title="@string/dolby_hp_virtualizer" /> diff --git a/dolby/src/co/aospa/dolby/xiaomi/DolbyAudioEffect.kt b/dolby/src/co/aospa/dolby/xiaomi/DolbyAudioEffect.kt index cdb9b5d..71f0b27 100644 --- a/dolby/src/co/aospa/dolby/xiaomi/DolbyAudioEffect.kt +++ b/dolby/src/co/aospa/dolby/xiaomi/DolbyAudioEffect.kt @@ -46,7 +46,7 @@ class DolbyAudioEffect(priority: Int, audioSession: Int) : AudioEffect( } } - fun resetProfileSpecificSettings() { + fun resetProfileSpecificSettings(profile: Int = this.profile) { dlog(TAG, "resetProfileSpecificSettings: profile=$profile") setIntParam(EFFECT_PARAM_RESET_PROFILE_SETTINGS, profile) } diff --git a/dolby/src/co/aospa/dolby/xiaomi/DolbyConstants.kt b/dolby/src/co/aospa/dolby/xiaomi/DolbyConstants.kt index 8d3af58..bd546bb 100644 --- a/dolby/src/co/aospa/dolby/xiaomi/DolbyConstants.kt +++ b/dolby/src/co/aospa/dolby/xiaomi/DolbyConstants.kt @@ -31,13 +31,24 @@ class DolbyConstants { const val PREF_ENABLE = "dolby_enable" const val PREF_PROFILE = "dolby_profile" const val PREF_PRESET = "dolby_preset" - const val PREF_VIRTUALIZER = "dolby_virtualizer" + const val PREF_HP_VIRTUALIZER = "dolby_virtualizer" + const val PREF_SPK_VIRTUALIZER = "dolby_spk_virtualizer" const val PREF_STEREO = "dolby_stereo" const val PREF_DIALOGUE = "dolby_dialogue" const val PREF_BASS = "dolby_bass" const val PREF_VOLUME = "dolby_volume" const val PREF_RESET = "dolby_reset" + val PROFILE_SPECIFIC_PREFS = setOf( + PREF_PRESET, + PREF_HP_VIRTUALIZER, + PREF_SPK_VIRTUALIZER, + PREF_STEREO, + PREF_DIALOGUE, + PREF_BASS, + PREF_VOLUME + ) + fun dlog(tag: String, msg: String) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(tag, msg) diff --git a/dolby/src/co/aospa/dolby/xiaomi/DolbyController.kt b/dolby/src/co/aospa/dolby/xiaomi/DolbyController.kt index f0abad0..3761fb2 100644 --- a/dolby/src/co/aospa/dolby/xiaomi/DolbyController.kt +++ b/dolby/src/co/aospa/dolby/xiaomi/DolbyController.kt @@ -90,99 +90,6 @@ internal class DolbyController private constructor( dolbyEffect.profile = value } - var preset: String - get() { - val gains = dolbyEffect.getDapParameter(DsParam.GEQ_BAND_GAINS) - return gains.joinToString(separator = ",").also { - dlog(TAG, "getPreset: $it") - } - } - set(value) { - dlog(TAG, "setPreset: $value") - checkEffect() - val gains = value.split(",") - .map { it.toInt() } - .toIntArray() - dolbyEffect.setDapParameter(DsParam.GEQ_BAND_GAINS, gains) - } - - var headphoneVirtEnabled: Boolean - get() = - dolbyEffect.getDapParameterBool(DsParam.HEADPHONE_VIRTUALIZER).also { - dlog(TAG, "getHeadphoneVirtEnabled: $it") - } - set(value) { - dlog(TAG, "setHeadphoneVirtEnabled: $value") - checkEffect() - dolbyEffect.setDapParameter(DsParam.HEADPHONE_VIRTUALIZER, value) - } - - var speakerVirtEnabled: Boolean - get() = - dolbyEffect.getDapParameterBool(DsParam.SPEAKER_VIRTUALIZER).also { - dlog(TAG, "getSpeakerVirtEnabled: $it") - } - set(value) { - dlog(TAG, "setSpeakerVirtEnabled: $value") - checkEffect() - dolbyEffect.setDapParameter(DsParam.SPEAKER_VIRTUALIZER, value) - } - - var bassEnhancerEnabled: Boolean - get() = - dolbyEffect.getDapParameterBool(DsParam.BASS_ENHANCER_ENABLE).also { - dlog(TAG, "getBassEnhancerEnabled: $it") - } - set(value) { - dlog(TAG, "setBassEnhancerEnabled: $value") - checkEffect() - dolbyEffect.setDapParameter(DsParam.BASS_ENHANCER_ENABLE, value) - } - - var volumeLevelerEnabled: Boolean - get() { - val enabled = dolbyEffect.getDapParameterBool(DsParam.VOLUME_LEVELER_ENABLE) - val amount = dolbyEffect.getDapParameterInt(DsParam.VOLUME_LEVELER_AMOUNT) - dlog(TAG, "getVolumeLevelerEnabled: enabled=$enabled amount=$amount") - return enabled && amount > 0 - } - set(value) { - dlog(TAG, "setVolumeLevelerEnabled: $value") - checkEffect() - dolbyEffect.setDapParameter(DsParam.VOLUME_LEVELER_ENABLE, value) - dolbyEffect.setDapParameter( - DsParam.VOLUME_LEVELER_AMOUNT, - if (value) VOLUME_LEVELER_AMOUNT else 0 - ) - } - - var stereoWideningAmount: Int - get() = - dolbyEffect.getDapParameterInt(DsParam.STEREO_WIDENING_AMOUNT).also { - dlog(TAG, "getStereoWideningAmount: $it") - } - set(value) { - dlog(TAG, "setStereoWideningAmount: $value") - checkEffect() - dolbyEffect.setDapParameter(DsParam.STEREO_WIDENING_AMOUNT, value) - } - - var dialogueEnhancerAmount: Int - get() { - val enabled = dolbyEffect.getDapParameterBool(DsParam.DIALOGUE_ENHANCER_ENABLE) - val amount = if (enabled) { - dolbyEffect.getDapParameterInt(DsParam.DIALOGUE_ENHANCER_AMOUNT) - } else 0 - dlog(TAG, "getDialogueEnhancerAmount: enabled=$enabled amount=$amount") - return amount - } - set(value) { - dlog(TAG, "setDialogueEnhancerAmount: $value") - checkEffect() - dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_ENABLE, (value > 0)) - dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_AMOUNT, value) - } - init { dlog(TAG, "initialized") } @@ -190,12 +97,58 @@ internal class DolbyController private constructor( fun onBootCompleted() { dlog(TAG, "onBootCompleted") - // Restore current profile now and on certain audio changes. - val on = dsOn - dolbyEffect.enabled = on - registerCallbacks = on - if (on) - setCurrentProfile() + // Restore our main settings + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + dsOn = prefs.getBoolean(DolbyConstants.PREF_ENABLE, true) + setCurrentProfile() + + context.resources.getStringArray(R.array.dolby_profile_values) + .map { it.toInt() } + .forEach { profile -> + // Reset dolby first to prevent it from loading bad settings + dolbyEffect.resetProfileSpecificSettings(profile) + // Now restore our profile-specific settings + restoreSettings(profile) + } + } + + private fun restoreSettings(profile: Int) { + dlog(TAG, "restoreSettings(profile=$profile)") + val prefs = context.getSharedPreferences("profile_$profile", Context.MODE_PRIVATE) + setPreset( + prefs.getString(DolbyConstants.PREF_PRESET, getPreset(profile)), + profile + ) + setHeadphoneVirtEnabled( + prefs.getBoolean(DolbyConstants.PREF_HP_VIRTUALIZER, getHeadphoneVirtEnabled(profile)), + profile + ) + setSpeakerVirtEnabled( + prefs.getBoolean(DolbyConstants.PREF_SPK_VIRTUALIZER, getSpeakerVirtEnabled(profile)), + profile + ) + setStereoWideningAmount( + prefs.getString( + DolbyConstants.PREF_STEREO, + getStereoWideningAmount(profile).toString() + ).toInt(), + profile + ) + setDialogueEnhancerAmount( + prefs.getString( + DolbyConstants.PREF_DIALOGUE, + getDialogueEnhancerAmount(profile).toString() + ).toInt(), + profile + ) + setBassEnhancerEnabled( + prefs.getBoolean(DolbyConstants.PREF_BASS, getBassEnhancerEnabled(profile)), + profile + ) + setVolumeLevelerEnabled( + prefs.getBoolean(DolbyConstants.PREF_VOLUME, getVolumeLevelerEnabled(profile)), + profile + ) } private fun checkEffect() { @@ -207,10 +160,6 @@ internal class DolbyController private constructor( } private fun setCurrentProfile() { - if (!dsOn) { - dlog(TAG, "setCurrentProfile: skip, dolby is off") - return - } dlog(TAG, "setCurrentProfile") val prefs = PreferenceManager.getDefaultSharedPreferences(context) profile = prefs.getString(DolbyConstants.PREF_PROFILE, "0" /*dynamic*/).toInt() @@ -227,8 +176,104 @@ internal class DolbyController private constructor( } fun resetProfileSpecificSettings() { + dlog(TAG, "resetProfileSpecificSettings") checkEffect() dolbyEffect.resetProfileSpecificSettings() + context.deleteSharedPreferences("profile_$profile") + } + + fun getPreset(profile: Int = this.profile): String { + val gains = dolbyEffect.getDapParameter(DsParam.GEQ_BAND_GAINS, profile) + return gains.joinToString(separator = ",").also { + dlog(TAG, "getPreset: $it") + } + } + + fun setPreset(value: String, profile: Int = this.profile) { + dlog(TAG, "setPreset: $value") + checkEffect() + val gains = value.split(",") + .map { it.toInt() } + .toIntArray() + dolbyEffect.setDapParameter(DsParam.GEQ_BAND_GAINS, gains, profile) + } + + fun getHeadphoneVirtEnabled(profile: Int = this.profile) = + dolbyEffect.getDapParameterBool(DsParam.HEADPHONE_VIRTUALIZER, profile).also { + dlog(TAG, "getHeadphoneVirtEnabled: $it") + } + + fun setHeadphoneVirtEnabled(value: Boolean, profile: Int = this.profile) { + dlog(TAG, "setHeadphoneVirtEnabled: $value") + checkEffect() + dolbyEffect.setDapParameter(DsParam.HEADPHONE_VIRTUALIZER, value, profile) + } + + fun getSpeakerVirtEnabled(profile: Int = this.profile) = + dolbyEffect.getDapParameterBool(DsParam.SPEAKER_VIRTUALIZER, profile).also { + dlog(TAG, "getSpeakerVirtEnabled: $it") + } + + fun setSpeakerVirtEnabled(value: Boolean, profile: Int = this.profile) { + dlog(TAG, "setSpeakerVirtEnabled: $value") + checkEffect() + dolbyEffect.setDapParameter(DsParam.SPEAKER_VIRTUALIZER, value, profile) + } + + fun getBassEnhancerEnabled(profile: Int = this.profile) = + dolbyEffect.getDapParameterBool(DsParam.BASS_ENHANCER_ENABLE, profile).also { + dlog(TAG, "getBassEnhancerEnabled: $it") + } + + fun setBassEnhancerEnabled(value: Boolean, profile: Int = this.profile) { + dlog(TAG, "setBassEnhancerEnabled: $value") + checkEffect() + dolbyEffect.setDapParameter(DsParam.BASS_ENHANCER_ENABLE, value, profile) + } + + fun getVolumeLevelerEnabled(profile: Int = this.profile): Boolean { + val enabled = dolbyEffect.getDapParameterBool(DsParam.VOLUME_LEVELER_ENABLE, profile) + val amount = dolbyEffect.getDapParameterInt(DsParam.VOLUME_LEVELER_AMOUNT, profile) + dlog(TAG, "getVolumeLevelerEnabled: enabled=$enabled amount=$amount") + return enabled && amount > 0 + } + + fun setVolumeLevelerEnabled(value: Boolean, profile: Int = this.profile) { + dlog(TAG, "setVolumeLevelerEnabled: $value") + checkEffect() + dolbyEffect.setDapParameter(DsParam.VOLUME_LEVELER_ENABLE, value, profile) + dolbyEffect.setDapParameter( + DsParam.VOLUME_LEVELER_AMOUNT, + if (value) VOLUME_LEVELER_AMOUNT else 0, + profile + ) + } + + fun getStereoWideningAmount(profile: Int = this.profile) = + dolbyEffect.getDapParameterInt(DsParam.STEREO_WIDENING_AMOUNT, profile).also { + dlog(TAG, "getStereoWideningAmount: $it") + } + + fun setStereoWideningAmount(value: Int, profile: Int = this.profile) { + dlog(TAG, "setStereoWideningAmount: $value") + checkEffect() + dolbyEffect.setDapParameter(DsParam.STEREO_WIDENING_AMOUNT, value, profile) + } + + fun getDialogueEnhancerAmount(profile: Int = this.profile): Int { + val enabled = dolbyEffect.getDapParameterBool(DsParam.DIALOGUE_ENHANCER_ENABLE, profile) + val amount = if (enabled) { + dolbyEffect.getDapParameterInt(DsParam.DIALOGUE_ENHANCER_AMOUNT, profile) + } else 0 + dlog(TAG, "getDialogueEnhancerAmount: enabled=$enabled amount=$amount") + return amount + } + + fun setDialogueEnhancerAmount(value: Int, profile: Int = this.profile) { + dlog(TAG, "setDialogueEnhancerAmount: $value") + checkEffect() + dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_ENABLE, (value > 0), profile) + dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_AMOUNT, value, profile) } companion object { diff --git a/dolby/src/co/aospa/dolby/xiaomi/DolbyPreferenceStore.kt b/dolby/src/co/aospa/dolby/xiaomi/DolbyPreferenceStore.kt new file mode 100644 index 0000000..918a37b --- /dev/null +++ b/dolby/src/co/aospa/dolby/xiaomi/DolbyPreferenceStore.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 Paranoid Android + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package co.aospa.dolby.xiaomi + +import android.content.Context +import android.content.SharedPreferences +import androidx.preference.PreferenceDataStore +import androidx.preference.PreferenceManager + +class DolbyPreferenceStore( + private val context: Context +) : PreferenceDataStore() { + + private val defaultSharedPrefs by lazy { + PreferenceManager.getDefaultSharedPreferences(context) + } + + private lateinit var profileSharedPrefs: SharedPreferences + + var profile = 0 + set(value) { + field = value + profileSharedPrefs = context.getSharedPreferences( + "profile_$value", + Context.MODE_PRIVATE + ) + } + + private fun getSharedPreferences(key: String) = + if (DolbyConstants.PROFILE_SPECIFIC_PREFS.contains(key)) { + profileSharedPrefs + } else { + defaultSharedPrefs + } + + override fun putBoolean(key: String, value: Boolean) = + getSharedPreferences(key).edit() + .putBoolean(key, value) + .apply() + + override fun getBoolean(key: String, defValue: Boolean) = + getSharedPreferences(key).getBoolean(key, defValue) + + override fun putInt(key: String, value: Int) = + getSharedPreferences(key).edit() + .putInt(key, value) + .apply() + + override fun getInt(key: String, defValue: Int) = + getSharedPreferences(key).getInt(key, defValue) + + override fun putString(key: String, value: String?) = + getSharedPreferences(key).edit() + .putString(key, value) + .apply() + + override fun getString(key: String, defValue: String?) = + getSharedPreferences(key).getString(key, defValue) +} diff --git a/dolby/src/co/aospa/dolby/xiaomi/DolbySettingsFragment.kt b/dolby/src/co/aospa/dolby/xiaomi/DolbySettingsFragment.kt index f2495f1..38a0c22 100644 --- a/dolby/src/co/aospa/dolby/xiaomi/DolbySettingsFragment.kt +++ b/dolby/src/co/aospa/dolby/xiaomi/DolbySettingsFragment.kt @@ -45,8 +45,11 @@ class DolbySettingsFragment : PreferenceFragment(), private val bassPref by lazy { findPreference(DolbyConstants.PREF_BASS)!! } - private val virtPref by lazy { - findPreference(DolbyConstants.PREF_VIRTUALIZER)!! + private val hpVirtPref by lazy { + findPreference(DolbyConstants.PREF_HP_VIRTUALIZER)!! + } + private val spkVirtPref by lazy { + findPreference(DolbyConstants.PREF_SPK_VIRTUALIZER)!! } private val volumePref by lazy { findPreference(DolbyConstants.PREF_VOLUME)!! @@ -83,14 +86,17 @@ class DolbySettingsFragment : PreferenceFragment(), dlog(TAG, "onCreatePreferences") addPreferencesFromResource(R.xml.dolby_settings) + val profile = dolbyController.profile + preferenceManager.preferenceDataStore = DolbyPreferenceStore(context).also { + it.profile = profile + } + val dsOn = dolbyController.dsOn switchBar.addOnSwitchChangeListener(this) switchBar.setChecked(dsOn) profilePref.onPreferenceChangeListener = this profilePref.setEnabled(dsOn) - - val profile = dolbyController.profile profilePref.apply { if (entryValues.contains(profile.toString())) { summary = "%s" @@ -101,7 +107,8 @@ class DolbySettingsFragment : PreferenceFragment(), } presetPref.onPreferenceChangeListener = this - virtPref.onPreferenceChangeListener = this + hpVirtPref.onPreferenceChangeListener = this + spkVirtPref.onPreferenceChangeListener = this stereoPref.onPreferenceChangeListener = this dialoguePref.onPreferenceChangeListener = this bassPref.onPreferenceChangeListener = this @@ -133,35 +140,38 @@ class DolbySettingsFragment : PreferenceFragment(), dlog(TAG, "onPreferenceChange: key=${preference.key} value=$newValue") when (preference.key) { DolbyConstants.PREF_PROFILE -> { - dolbyController.profile = newValue.toString().toInt() + val profile = newValue.toString().toInt() + dolbyController.profile = profile + (preferenceManager.preferenceDataStore as DolbyPreferenceStore).profile = profile updateProfileSpecificPrefs() } DolbyConstants.PREF_PRESET -> { - dolbyController.preset = newValue.toString() + dolbyController.setPreset(newValue.toString()) } - DolbyConstants.PREF_VIRTUALIZER -> { - if (isOnSpeaker) - dolbyController.speakerVirtEnabled = newValue as Boolean - else - dolbyController.headphoneVirtEnabled = newValue as Boolean + DolbyConstants.PREF_SPK_VIRTUALIZER -> { + dolbyController.setSpeakerVirtEnabled(newValue as Boolean) + } + + DolbyConstants.PREF_HP_VIRTUALIZER -> { + dolbyController.setHeadphoneVirtEnabled(newValue as Boolean) } DolbyConstants.PREF_STEREO -> { - dolbyController.stereoWideningAmount = newValue.toString().toInt() + dolbyController.setStereoWideningAmount(newValue.toString().toInt()) } DolbyConstants.PREF_DIALOGUE -> { - dolbyController.dialogueEnhancerAmount = newValue.toString().toInt() + dolbyController.setDialogueEnhancerAmount(newValue.toString().toInt()) } DolbyConstants.PREF_BASS -> { - dolbyController.bassEnhancerEnabled = newValue as Boolean + dolbyController.setBassEnhancerEnabled(newValue as Boolean) } DolbyConstants.PREF_VOLUME -> { - dolbyController.volumeLevelerEnabled = newValue as Boolean + dolbyController.setVolumeLevelerEnabled(newValue as Boolean) } else -> return false @@ -194,16 +204,17 @@ class DolbySettingsFragment : PreferenceFragment(), val enable = dsOn && (currentProfile != -1) presetPref.setEnabled(enable) - virtPref.setEnabled(enable) + spkVirtPref.setEnabled(enable) dialoguePref.setEnabled(enable) volumePref.setEnabled(enable) resetPref.setEnabled(enable) + hpVirtPref.setEnabled(enable && !isOnSpeaker) stereoPref.setEnabled(enable && !isOnSpeaker) bassPref.setEnabled(enable && !isOnSpeaker) if (!enable) return - val preset = dolbyController.preset + val preset = dolbyController.getPreset(currentProfile) presetPref.apply { if (entryValues.contains(preset)) { summary = "%s" @@ -213,7 +224,7 @@ class DolbySettingsFragment : PreferenceFragment(), } } - val deValue = dolbyController.dialogueEnhancerAmount.toString() + val deValue = dolbyController.getDialogueEnhancerAmount(currentProfile).toString() dialoguePref.apply { if (entryValues.contains(deValue)) { summary = "%s" @@ -223,22 +234,18 @@ class DolbySettingsFragment : PreferenceFragment(), } } - virtPref.setChecked(if (isOnSpeaker) { - dolbyController.speakerVirtEnabled - } else { - dolbyController.headphoneVirtEnabled - }) - - volumePref.setChecked(dolbyController.volumeLevelerEnabled) + spkVirtPref.setChecked(dolbyController.getSpeakerVirtEnabled(currentProfile)) + volumePref.setChecked(dolbyController.getVolumeLevelerEnabled(currentProfile)) // below prefs are not enabled on loudspeaker if (isOnSpeaker) { stereoPref.summary = headphoneRes bassPref.summary = headphoneRes + hpVirtPref.summary = headphoneRes return } - val swValue = dolbyController.stereoWideningAmount.toString() + val swValue = dolbyController.getStereoWideningAmount(currentProfile).toString() stereoPref.apply { if (entryValues.contains(swValue)) { summary = "%s" @@ -249,7 +256,12 @@ class DolbySettingsFragment : PreferenceFragment(), } bassPref.apply { - setChecked(dolbyController.bassEnhancerEnabled) + setChecked(dolbyController.getBassEnhancerEnabled(currentProfile)) + summary = null + } + + hpVirtPref.apply { + setChecked(dolbyController.getHeadphoneVirtEnabled(currentProfile)) summary = null } }