mirror of
https://github.com/Michatec/Radio.git
synced 2026-05-31 08:12:39 +02:00
feat(audio): add 10-band equalizer and audio presets
This commit is contained in:
@@ -9,10 +9,25 @@ import androidx.preference.SeekBarPreference
|
||||
import com.michatec.radio.helpers.PreferencesHelper
|
||||
|
||||
/*
|
||||
* EqualizerFragment class: Handles audio frequency settings
|
||||
* EqualizerFragment class: Handles audio frequency settings with 10-band EQ
|
||||
*/
|
||||
class EqualizerFragment : PreferenceFragmentCompat() {
|
||||
|
||||
// EQ band frequencies matching radio.cpp
|
||||
private val eqFrequencies = arrayOf("31 Hz", "62 Hz", "125 Hz", "250 Hz", "500 Hz", "1 kHz", "2 kHz", "4 kHz", "8 kHz", "16 kHz")
|
||||
private val eqKeys = arrayOf(
|
||||
Keys.PREF_EQ_LOW, // Band 0: 31 Hz
|
||||
Keys.PREF_EQ_BAND_1, // Band 1: 62 Hz
|
||||
Keys.PREF_EQ_BAND_2, // Band 2: 125 Hz
|
||||
Keys.PREF_EQ_BAND_3, // Band 3: 250 Hz
|
||||
Keys.PREF_EQ_BAND_4, // Band 4: 500 Hz
|
||||
Keys.PREF_EQ_BAND_5, // Band 5: 1 kHz
|
||||
Keys.PREF_EQ_MID, // Band 6: 2 kHz
|
||||
Keys.PREF_EQ_BAND_6, // Band 7: 4 kHz
|
||||
Keys.PREF_EQ_BAND_7, // Band 8: 8 kHz
|
||||
Keys.PREF_EQ_HIGH // Band 9: 16 kHz
|
||||
)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.pref_equalizer_title)
|
||||
@@ -28,46 +43,25 @@ class EqualizerFragment : PreferenceFragmentCompat() {
|
||||
resetPreference.setIcon(R.drawable.ic_refresh_24dp)
|
||||
resetPreference.setOnPreferenceClickListener {
|
||||
PreferencesHelper.resetEqualizer()
|
||||
// Manually update SeekBars to 0
|
||||
findPreference<SeekBarPreference>(Keys.PREF_EQ_LOW)?.value = 0
|
||||
findPreference<SeekBarPreference>(Keys.PREF_EQ_MID)?.value = 0
|
||||
findPreference<SeekBarPreference>(Keys.PREF_EQ_HIGH)?.value = 0
|
||||
for (key in eqKeys) {
|
||||
findPreference<SeekBarPreference>(key)?.value = 0
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
screen.addPreference(resetPreference)
|
||||
|
||||
// EQ Low
|
||||
val eqLow = SeekBarPreference(context)
|
||||
eqLow.title = getString(R.string.pref_eq_low_title)
|
||||
eqLow.key = Keys.PREF_EQ_LOW
|
||||
eqLow.setIcon(R.drawable.ic_music_note_24dp)
|
||||
eqLow.min = -12
|
||||
eqLow.max = 12
|
||||
eqLow.showSeekBarValue = true
|
||||
eqLow.setDefaultValue(0)
|
||||
screen.addPreference(eqLow)
|
||||
|
||||
// EQ Mid
|
||||
val eqMid = SeekBarPreference(context)
|
||||
eqMid.title = getString(R.string.pref_eq_mid_title)
|
||||
eqMid.key = Keys.PREF_EQ_MID
|
||||
eqMid.setIcon(R.drawable.ic_music_note_24dp)
|
||||
eqMid.min = -12
|
||||
eqMid.max = 12
|
||||
eqMid.showSeekBarValue = true
|
||||
eqMid.setDefaultValue(0)
|
||||
screen.addPreference(eqMid)
|
||||
|
||||
// EQ High
|
||||
val eqHigh = SeekBarPreference(context)
|
||||
eqHigh.title = getString(R.string.pref_eq_high_title)
|
||||
eqHigh.key = Keys.PREF_EQ_HIGH
|
||||
eqHigh.setIcon(R.drawable.ic_music_note_24dp)
|
||||
eqHigh.min = -12
|
||||
eqHigh.max = 12
|
||||
eqHigh.showSeekBarValue = true
|
||||
eqHigh.setDefaultValue(0)
|
||||
screen.addPreference(eqHigh)
|
||||
// Create 10-band EQ
|
||||
for (i in eqKeys.indices) {
|
||||
val eqBand = SeekBarPreference(context)
|
||||
eqBand.title = "Equalizer: ${eqFrequencies[i]}"
|
||||
eqBand.key = eqKeys[i]
|
||||
eqBand.setIcon(R.drawable.ic_music_note_24dp)
|
||||
eqBand.min = -12
|
||||
eqBand.max = 12
|
||||
eqBand.showSeekBarValue = true
|
||||
eqBand.setDefaultValue(0)
|
||||
screen.addPreference(eqBand)
|
||||
}
|
||||
|
||||
preferenceScreen = screen
|
||||
}
|
||||
|
||||
@@ -66,6 +66,30 @@ object Keys {
|
||||
const val PREF_EQ_LOW: String = "EQ_LOW"
|
||||
const val PREF_EQ_MID: String = "EQ_MID"
|
||||
const val PREF_EQ_HIGH: String = "EQ_HIGH"
|
||||
const val PREF_EQUALIZER: String = "EQUALIZER_SETTINGS"
|
||||
const val PREF_EQ_BAND_1: String = "EQ_BAND_1"
|
||||
const val PREF_EQ_BAND_2: String = "EQ_BAND_2"
|
||||
const val PREF_EQ_BAND_3: String = "EQ_BAND_3"
|
||||
const val PREF_EQ_BAND_4: String = "EQ_BAND_4"
|
||||
const val PREF_EQ_BAND_5: String = "EQ_BAND_5"
|
||||
const val PREF_EQ_BAND_6: String = "EQ_BAND_6"
|
||||
const val PREF_EQ_BAND_7: String = "EQ_BAND_7"
|
||||
const val PREF_EQ_BAND_8: String = "EQ_BAND_8"
|
||||
const val PREF_PRESET_SELECTED: String = "PRESET_SELECTED"
|
||||
const val PREF_PRESET_EQ_BAND_0: String = "PRESET_EQ_BAND_0"
|
||||
const val PREF_PRESET_EQ_BAND_1: String = "PRESET_EQ_BAND_1"
|
||||
const val PREF_PRESET_EQ_BAND_2: String = "PRESET_EQ_BAND_2"
|
||||
const val PREF_PRESET_EQ_BAND_3: String = "PRESET_EQ_BAND_3"
|
||||
const val PREF_PRESET_EQ_BAND_4: String = "PRESET_EQ_BAND_4"
|
||||
const val PREF_PRESET_EQ_BAND_5: String = "PRESET_EQ_BAND_5"
|
||||
const val PREF_PRESET_EQ_BAND_6: String = "PRESET_EQ_BAND_6"
|
||||
const val PREF_PRESET_EQ_BAND_7: String = "PRESET_EQ_BAND_7"
|
||||
const val PREF_PRESET_EQ_BAND_8: String = "PRESET_EQ_BAND_8"
|
||||
const val PREF_PRESET_EQ_BAND_9: String = "PRESET_EQ_BAND_9"
|
||||
const val PREF_PRESET_BASS_BOOST: String = "PRESET_BASS_BOOST"
|
||||
const val PREF_PRESET_REVERB: String = "PRESET_REVERB"
|
||||
const val PREF_PRESET_DRC: String = "PRESET_DRC"
|
||||
const val PREF_PRESET_STEREO_WIDTH: String = "PRESET_STEREO_WIDTH"
|
||||
|
||||
// default const values
|
||||
const val DEFAULT_SIZE_OF_METADATA_HISTORY: Int = 25
|
||||
|
||||
@@ -286,20 +286,61 @@ class PlayerService : MediaLibraryService(), SharedPreferences.OnSharedPreferenc
|
||||
|
||||
/* Applies audio effects based on preferences */
|
||||
private fun applyAudioEffects() {
|
||||
nativeAudioProcessor.enableBassBoost(PreferencesHelper.loadBassBoost())
|
||||
nativeAudioProcessor.setReverb(PreferencesHelper.loadReverb())
|
||||
nativeAudioProcessor.enableDrc(PreferencesHelper.loadDrcEnabled())
|
||||
nativeAudioProcessor.setEq(0, PreferencesHelper.loadEqLow())
|
||||
nativeAudioProcessor.setEq(1, PreferencesHelper.loadEqMid())
|
||||
nativeAudioProcessor.setEq(2, PreferencesHelper.loadEqHigh())
|
||||
val selectedPreset = PreferencesHelper.loadSelectedPreset()
|
||||
if (selectedPreset.isNotEmpty()) {
|
||||
applyPreset(selectedPreset)
|
||||
} else {
|
||||
// Apply manual settings
|
||||
nativeAudioProcessor.enableBassBoost(PreferencesHelper.loadBassBoost())
|
||||
nativeAudioProcessor.setReverb(PreferencesHelper.loadReverb())
|
||||
nativeAudioProcessor.enableDrc(PreferencesHelper.loadDrcEnabled())
|
||||
nativeAudioProcessor.setWidth(1f)
|
||||
// Apply all 10 EQ bands
|
||||
val eqGains = FloatArray(10)
|
||||
for (i in 0 until 10) {
|
||||
eqGains[i] = PreferencesHelper.loadEqBand(i).toFloat()
|
||||
}
|
||||
nativeAudioProcessor.setEqAll(eqGains)
|
||||
}
|
||||
}
|
||||
|
||||
/* Applies a saved preset */
|
||||
private fun applyPreset(presetName: String) {
|
||||
when (presetName) {
|
||||
getString(R.string.pref_preset_rock) -> nativeAudioProcessor.setPresetRock()
|
||||
getString(R.string.pref_preset_pop) -> nativeAudioProcessor.setPresetPop()
|
||||
getString(R.string.pref_preset_jazz) -> nativeAudioProcessor.setPresetJazz()
|
||||
getString(R.string.pref_preset_flat) -> nativeAudioProcessor.setPresetFlat()
|
||||
else -> {
|
||||
// Custom preset - load from preferences
|
||||
nativeAudioProcessor.enableDrc(PreferencesHelper.loadPresetDrc())
|
||||
nativeAudioProcessor.setReverb(PreferencesHelper.loadPresetReverb())
|
||||
nativeAudioProcessor.setWidth(PreferencesHelper.loadPresetStereoWidth())
|
||||
nativeAudioProcessor.enableBassBoost(PreferencesHelper.loadPresetBassBoost())
|
||||
val eqGains = FloatArray(10)
|
||||
for (i in 0 until 10) {
|
||||
eqGains[i] = PreferencesHelper.loadPresetEqBand(i).toFloat()
|
||||
}
|
||||
nativeAudioProcessor.setEqAll(eqGains)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Overrides onSharedPreferenceChanged from SharedPreferences.OnSharedPreferenceChangeListener */
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
when (key) {
|
||||
Keys.PREF_BASS_BOOST, Keys.PREF_REVERB, Keys.PREF_DRC,
|
||||
Keys.PREF_EQ_LOW, Keys.PREF_EQ_MID, Keys.PREF_EQ_HIGH -> {
|
||||
Keys.PREF_BASS_BOOST, Keys.PREF_REVERB, Keys.PREF_DRC,
|
||||
Keys.PREF_EQ_LOW, Keys.PREF_EQ_MID, Keys.PREF_EQ_HIGH,
|
||||
Keys.PREF_EQ_BAND_1, Keys.PREF_EQ_BAND_2, Keys.PREF_EQ_BAND_3,
|
||||
Keys.PREF_EQ_BAND_4, Keys.PREF_EQ_BAND_5, Keys.PREF_EQ_BAND_6,
|
||||
Keys.PREF_EQ_BAND_7, Keys.PREF_EQ_BAND_8,
|
||||
Keys.PREF_PRESET_SELECTED,
|
||||
Keys.PREF_PRESET_EQ_BAND_0, Keys.PREF_PRESET_EQ_BAND_1, Keys.PREF_PRESET_EQ_BAND_2,
|
||||
Keys.PREF_PRESET_EQ_BAND_3, Keys.PREF_PRESET_EQ_BAND_4, Keys.PREF_PRESET_EQ_BAND_5,
|
||||
Keys.PREF_PRESET_EQ_BAND_6, Keys.PREF_PRESET_EQ_BAND_7, Keys.PREF_PRESET_EQ_BAND_8,
|
||||
Keys.PREF_PRESET_EQ_BAND_9,
|
||||
Keys.PREF_PRESET_BASS_BOOST, Keys.PREF_PRESET_REVERB,
|
||||
Keys.PREF_PRESET_DRC, Keys.PREF_PRESET_STEREO_WIDTH -> {
|
||||
applyAudioEffects()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.*
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.michatec.radio.dialogs.ErrorDialog
|
||||
import com.michatec.radio.dialogs.PresetSelectionDialog
|
||||
import com.michatec.radio.dialogs.ThemeSelectionDialog
|
||||
import com.michatec.radio.dialogs.YesNoDialog
|
||||
import com.michatec.radio.helpers.*
|
||||
@@ -30,7 +31,7 @@ import java.util.*
|
||||
/*
|
||||
* SettingsFragment class
|
||||
*/
|
||||
class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogListener, ThemeSelectionDialog.ThemeSelectionDialogListener {
|
||||
class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogListener, ThemeSelectionDialog.ThemeSelectionDialogListener, PresetSelectionDialog.PresetSelectionDialogListener {
|
||||
|
||||
|
||||
/* Define log tag */
|
||||
@@ -52,6 +53,9 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
val context = preferenceManager.context
|
||||
val screen = preferenceManager.createPreferenceScreen(context)
|
||||
|
||||
// Load current preset once
|
||||
val currentPreset = PreferencesHelper.loadSelectedPreset()
|
||||
|
||||
// set up "App Theme" preference
|
||||
val preferenceThemeSelection = Preference(activity as Context)
|
||||
preferenceThemeSelection.title = getString(R.string.pref_theme_selection_title)
|
||||
@@ -190,6 +194,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
preferenceBassBoost.title = getString(R.string.pref_bass_boost_title)
|
||||
preferenceBassBoost.setIcon(R.drawable.ic_music_note_24dp)
|
||||
preferenceBassBoost.key = Keys.PREF_BASS_BOOST
|
||||
preferenceBassBoost.isEnabled = currentPreset.isEmpty()
|
||||
preferenceBassBoost.summary = getString(R.string.pref_bass_boost_summary)
|
||||
preferenceBassBoost.setDefaultValue(false)
|
||||
|
||||
@@ -198,6 +203,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
preferenceReverb.title = getString(R.string.pref_reverb_title)
|
||||
preferenceReverb.setIcon(R.drawable.ic_music_note_24dp)
|
||||
preferenceReverb.key = Keys.PREF_REVERB
|
||||
preferenceReverb.isEnabled = currentPreset.isEmpty()
|
||||
preferenceReverb.summary = getString(R.string.pref_reverb_summary)
|
||||
preferenceReverb.setDefaultValue(false)
|
||||
|
||||
@@ -206,14 +212,39 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
preferenceDrc.title = getString(R.string.pref_drc_title)
|
||||
preferenceDrc.setIcon(R.drawable.ic_music_note_24dp)
|
||||
preferenceDrc.key = Keys.PREF_DRC
|
||||
preferenceDrc.isEnabled = currentPreset.isEmpty()
|
||||
preferenceDrc.summary = getString(R.string.pref_drc_summary)
|
||||
preferenceDrc.setDefaultValue(true)
|
||||
|
||||
// set up "Preset Selection" preference
|
||||
val preferencePresetSelection = Preference(context)
|
||||
preferencePresetSelection.title = getString(R.string.pref_preset_selection_title)
|
||||
preferencePresetSelection.setIcon(R.drawable.ic_music_note_24dp)
|
||||
preferencePresetSelection.key = Keys.PREF_PRESET_SELECTED
|
||||
val presetSummary = currentPreset.ifEmpty {
|
||||
getString(R.string.pref_preset_none)
|
||||
}
|
||||
preferencePresetSelection.summary = "${getString(R.string.pref_preset_selection_summary)}: $presetSummary"
|
||||
preferencePresetSelection.setOnPreferenceClickListener {
|
||||
PresetSelectionDialog(this).show(activity as Context)
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
||||
// Initialize EQ control states based on current preset
|
||||
updateEqControlStates()
|
||||
|
||||
// set up "Equalizer" preference entry
|
||||
val preferenceEqualizer = Preference(context)
|
||||
preferenceEqualizer.title = getString(R.string.pref_equalizer_title)
|
||||
preferenceEqualizer.setIcon(R.drawable.ic_music_note_24dp)
|
||||
preferenceEqualizer.summary = getString(R.string.pref_equalizer_summary)
|
||||
preferenceEqualizer.key = Keys.PREF_EQUALIZER
|
||||
if (currentPreset.isEmpty()) {
|
||||
preferenceEqualizer.summary = getString(R.string.pref_equalizer_summary)
|
||||
preferenceEqualizer.isEnabled = true
|
||||
} else {
|
||||
preferenceEqualizer.summary = getString(R.string.pref_equalizer_summary_off)
|
||||
preferenceEqualizer.isEnabled = false
|
||||
}
|
||||
preferenceEqualizer.setOnPreferenceClickListener {
|
||||
findNavController().navigate(R.id.action_settings_to_equalizer)
|
||||
return@setOnPreferenceClickListener true
|
||||
@@ -295,6 +326,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
preferenceCategoryAudioEffects.addPreference(preferenceBassBoost)
|
||||
preferenceCategoryAudioEffects.addPreference(preferenceReverb)
|
||||
preferenceCategoryAudioEffects.addPreference(preferenceDrc)
|
||||
preferenceCategoryAudioEffects.addPreference(preferencePresetSelection)
|
||||
preferenceCategoryAudioEffects.addPreference(preferenceEqualizer)
|
||||
|
||||
screen.addPreference(preferenceCategoryMaintenance)
|
||||
@@ -340,6 +372,49 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
}
|
||||
|
||||
|
||||
/* Overrides onPresetSelectionDialog from PresetSelectionDialogListener */
|
||||
override fun onPresetSelectionDialog(dialogResult: Boolean, selectedPreset: String) {
|
||||
if (dialogResult) {
|
||||
// update summary
|
||||
val presetPreference = findPreference<Preference>(Keys.PREF_PRESET_SELECTED)
|
||||
val presetSummary = selectedPreset.ifEmpty {
|
||||
getString(R.string.pref_preset_none)
|
||||
}
|
||||
presetPreference?.summary = "${getString(R.string.pref_preset_selection_summary)}: $presetSummary"
|
||||
|
||||
// Enable/disable manual EQ controls based on preset selection
|
||||
updateEqControlStates()
|
||||
}
|
||||
}
|
||||
|
||||
/* Updates the enabled/disabled state of EQ controls based on preset selection */
|
||||
private fun updateEqControlStates() {
|
||||
val currentPreset = PreferencesHelper.loadSelectedPreset()
|
||||
val isPresetSelected = currentPreset.isNotEmpty()
|
||||
|
||||
// Update Bass Boost
|
||||
findPreference<Preference>(Keys.PREF_BASS_BOOST)?.isEnabled = !isPresetSelected
|
||||
|
||||
// Update Reverb
|
||||
findPreference<Preference>(Keys.PREF_REVERB)?.isEnabled = !isPresetSelected
|
||||
|
||||
// Update DRC
|
||||
findPreference<Preference>(Keys.PREF_DRC)?.isEnabled = !isPresetSelected
|
||||
|
||||
// Update Equalizer with proper key
|
||||
val preferenceEqualizer = findPreference<Preference>(Keys.PREF_EQUALIZER)
|
||||
if (preferenceEqualizer != null) {
|
||||
if (isPresetSelected) {
|
||||
preferenceEqualizer.summary = getString(R.string.pref_equalizer_summary_off)
|
||||
preferenceEqualizer.isEnabled = false
|
||||
} else {
|
||||
preferenceEqualizer.summary = getString(R.string.pref_equalizer_summary)
|
||||
preferenceEqualizer.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Overrides onYesNoDialog from YesNoDialogListener */
|
||||
override fun onYesNoDialog(
|
||||
type: Int,
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.michatec.radio.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.RadioButton
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat.getString
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.michatec.radio.R
|
||||
import com.michatec.radio.helpers.PreferencesHelper
|
||||
|
||||
|
||||
/*
|
||||
* PresetSelectionDialog class
|
||||
*/
|
||||
class PresetSelectionDialog(private var presetSelectionDialogListener: PresetSelectionDialogListener) {
|
||||
|
||||
/* Interface used to communicate back to activity */
|
||||
interface PresetSelectionDialogListener {
|
||||
fun onPresetSelectionDialog(dialogResult: Boolean, selectedPreset: String)
|
||||
}
|
||||
|
||||
|
||||
/* Main class variables */
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
|
||||
/* Construct and show dialog */
|
||||
fun show(context: Context) {
|
||||
// prepare dialog builder
|
||||
val builder = MaterialAlertDialogBuilder(context)
|
||||
|
||||
// inflate custom layout
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(R.layout.dialog_preset_selection, null)
|
||||
|
||||
// find radio buttons
|
||||
val radioGroup = view.findViewById<android.widget.RadioGroup>(R.id.preset_radio_group)
|
||||
val radioNone = view.findViewById<RadioButton>(R.id.radio_preset_none)
|
||||
val radioRock = view.findViewById<RadioButton>(R.id.radio_preset_rock)
|
||||
val radioPop = view.findViewById<RadioButton>(R.id.radio_preset_pop)
|
||||
val radioJazz = view.findViewById<RadioButton>(R.id.radio_preset_jazz)
|
||||
val radioFlat = view.findViewById<RadioButton>(R.id.radio_preset_flat)
|
||||
|
||||
// set current selection
|
||||
val currentPreset = PreferencesHelper.loadSelectedPreset()
|
||||
when (currentPreset) {
|
||||
"" -> radioNone.isChecked = true
|
||||
getString(context, R.string.pref_preset_rock) -> radioRock.isChecked = true
|
||||
getString(context, R.string.pref_preset_pop) -> radioPop.isChecked = true
|
||||
getString(context, R.string.pref_preset_jazz) -> radioJazz.isChecked = true
|
||||
getString(context, R.string.pref_preset_flat) -> radioFlat.isChecked = true
|
||||
else -> radioNone.isChecked = true
|
||||
}
|
||||
|
||||
// set up radio group listener
|
||||
radioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||
val selectedPreset = when (checkedId) {
|
||||
R.id.radio_preset_none -> ""
|
||||
R.id.radio_preset_rock -> getString(context, R.string.pref_preset_rock)
|
||||
R.id.radio_preset_pop -> getString(context, R.string.pref_preset_pop)
|
||||
R.id.radio_preset_jazz -> getString(context, R.string.pref_preset_jazz)
|
||||
R.id.radio_preset_flat -> getString(context, R.string.pref_preset_flat)
|
||||
else -> ""
|
||||
}
|
||||
// save preset selection to preferences
|
||||
PreferencesHelper.saveSelectedPreset(selectedPreset)
|
||||
// notify listener
|
||||
presetSelectionDialogListener.onPresetSelectionDialog(true, selectedPreset)
|
||||
// dismiss dialog
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
// set custom view
|
||||
builder.setView(view)
|
||||
|
||||
// handle outside-click as cancel
|
||||
builder.setOnCancelListener {
|
||||
presetSelectionDialogListener.onPresetSelectionDialog(false, "")
|
||||
}
|
||||
|
||||
// display dialog
|
||||
dialog = builder.create()
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
@@ -18,41 +18,90 @@ class NativeAudioProcessor : BaseAudioProcessor() {
|
||||
}
|
||||
}
|
||||
|
||||
// JNI Methods
|
||||
// ===== JNI =====
|
||||
private external fun setDrcEnabled(enabled: Boolean)
|
||||
private external fun setReverbMix(mix: Float)
|
||||
private external fun setEqBand(band: Int, gainDb: Float)
|
||||
private external fun setBassBoost(gainDb: Float)
|
||||
private external fun processAudio(data: ShortArray, size: Int)
|
||||
private external fun setStereoWidth(width: Float)
|
||||
private external fun processAudioDirect(buf: ByteBuffer, size: Int)
|
||||
private external fun getFftData(): FloatArray
|
||||
|
||||
// Public API
|
||||
// ===== API =====
|
||||
fun enableDrc(enabled: Boolean) = setDrcEnabled(enabled)
|
||||
fun setReverb(mix: Float) = setReverbMix(mix)
|
||||
fun setEq(band: Int, gainDb: Float) = setEqBand(band, gainDb)
|
||||
fun setEqAll(gains: FloatArray) {
|
||||
gains.forEachIndexed { i, g -> setEq(i, g) }
|
||||
}
|
||||
fun enableBassBoost(gainDb: Float) = setBassBoost(gainDb)
|
||||
fun setWidth(width: Float) = setStereoWidth(width)
|
||||
|
||||
@Suppress("unused")
|
||||
fun getVisualizer(): FloatArray {
|
||||
val raw = getFftData()
|
||||
val out = FloatArray(raw.size)
|
||||
for (i in raw.indices) out[i] = kotlin.math.log10(1f + raw[i])
|
||||
return out
|
||||
}
|
||||
|
||||
// ===== AudioProcessor Overrides =====
|
||||
override fun onConfigure(inputAudioFormat: AudioFormat): AudioFormat {
|
||||
if (inputAudioFormat.encoding != C.ENCODING_PCM_16BIT) {
|
||||
if (inputAudioFormat.encoding != C.ENCODING_PCM_16BIT)
|
||||
throw AudioProcessor.UnhandledAudioFormatException(inputAudioFormat)
|
||||
}
|
||||
return inputAudioFormat
|
||||
}
|
||||
|
||||
override fun queueInput(inputBuffer: ByteBuffer) {
|
||||
val remaining = inputBuffer.remaining()
|
||||
if (remaining == 0) return
|
||||
val size = inputBuffer.remaining()
|
||||
if (size == 0) return
|
||||
|
||||
val shortArraySize = remaining / 2
|
||||
val shortArray = ShortArray(shortArraySize)
|
||||
// Direct ByteBuffer -> JNI
|
||||
inputBuffer.order(ByteOrder.nativeOrder())
|
||||
processAudioDirect(inputBuffer, size)
|
||||
|
||||
inputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer().get(shortArray)
|
||||
// Replace output buffer
|
||||
val out = replaceOutputBuffer(size)
|
||||
out.order(ByteOrder.nativeOrder())
|
||||
|
||||
processAudio(shortArray, shortArraySize)
|
||||
// Mark as processed and copy to output
|
||||
val currentPos = inputBuffer.position()
|
||||
out.put(inputBuffer)
|
||||
inputBuffer.position(currentPos + size)
|
||||
|
||||
val outputBuffer = replaceOutputBuffer(remaining)
|
||||
outputBuffer.asShortBuffer().put(shortArray)
|
||||
outputBuffer.limit(remaining)
|
||||
out.flip()
|
||||
}
|
||||
|
||||
inputBuffer.position(inputBuffer.limit())
|
||||
// ===== Presets =====
|
||||
fun setPresetRock() {
|
||||
enableDrc(true)
|
||||
setReverb(0.2f)
|
||||
setWidth(1.1f)
|
||||
setEqAll(floatArrayOf(2f, 1f, 0f, -1f, -1f, 0f, 1f, 2f, 2f, 3f))
|
||||
enableBassBoost(1.5f)
|
||||
}
|
||||
|
||||
fun setPresetPop() {
|
||||
enableDrc(true)
|
||||
setReverb(0.15f)
|
||||
setWidth(1.05f)
|
||||
setEqAll(floatArrayOf(1f, 1f, 0f, 0f, 0f, 0f, 1f, 2f, 2f, 1f))
|
||||
enableBassBoost(1.0f)
|
||||
}
|
||||
|
||||
fun setPresetJazz() {
|
||||
enableDrc(false)
|
||||
setReverb(0.15f)
|
||||
setWidth(1.0f)
|
||||
setEqAll(floatArrayOf(0f, 0f, 1f, 1f, 0f, 0f, 1f, 1f, 0f, 0f))
|
||||
enableBassBoost(0.5f)
|
||||
}
|
||||
|
||||
fun setPresetFlat() {
|
||||
enableDrc(false)
|
||||
setReverb(0f)
|
||||
setWidth(1f)
|
||||
setEqAll(FloatArray(10))
|
||||
enableBassBoost(0f)
|
||||
}
|
||||
}
|
||||
@@ -257,7 +257,7 @@ object PreferencesHelper {
|
||||
|
||||
/* Loads Bass Boost gain */
|
||||
fun loadBassBoost(): Float {
|
||||
return if (sharedPreferences.getBoolean(Keys.PREF_BASS_BOOST, false)) 5.0f else 0.0f
|
||||
return if (sharedPreferences.getBoolean(Keys.PREF_BASS_BOOST, false)) 1.5f else 0.0f
|
||||
}
|
||||
|
||||
|
||||
@@ -272,10 +272,69 @@ object PreferencesHelper {
|
||||
return sharedPreferences.getBoolean(Keys.PREF_DRC, false)
|
||||
}
|
||||
|
||||
/* Loads EQ gains */
|
||||
fun loadEqLow(): Float = sharedPreferences.getInt(Keys.PREF_EQ_LOW, 0).toFloat()
|
||||
fun loadEqMid(): Float = sharedPreferences.getInt(Keys.PREF_EQ_MID, 0).toFloat()
|
||||
fun loadEqHigh(): Float = sharedPreferences.getInt(Keys.PREF_EQ_HIGH, 0).toFloat()
|
||||
/* Loads all EQ bands (10 bands for full range) */
|
||||
fun loadEqBand(band: Int): Int {
|
||||
return when (band) {
|
||||
0 -> sharedPreferences.getInt(Keys.PREF_EQ_LOW, 0)
|
||||
1 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_1, 0)
|
||||
2 -> sharedPreferences.getInt(Keys.PREF_EQ_MID, 0)
|
||||
3 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_3, 0)
|
||||
4 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_4, 0)
|
||||
5 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_5, 0)
|
||||
6 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_6, 0)
|
||||
7 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_7, 0)
|
||||
8 -> sharedPreferences.getInt(Keys.PREF_EQ_BAND_8, 0)
|
||||
9 -> sharedPreferences.getInt(Keys.PREF_EQ_HIGH, 0)
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
/* Loads selected preset name */
|
||||
fun loadSelectedPreset(): String {
|
||||
return sharedPreferences.getString(Keys.PREF_PRESET_SELECTED, "") ?: ""
|
||||
}
|
||||
|
||||
/* Saves selected preset name */
|
||||
fun saveSelectedPreset(preset: String) {
|
||||
sharedPreferences.edit { putString(Keys.PREF_PRESET_SELECTED, preset) }
|
||||
}
|
||||
|
||||
/* Loads preset EQ band values */
|
||||
fun loadPresetEqBand(band: Int): Int {
|
||||
return when (band) {
|
||||
0 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_0, 0)
|
||||
1 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_1, 0)
|
||||
2 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_2, 0)
|
||||
3 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_3, 0)
|
||||
4 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_4, 0)
|
||||
5 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_5, 0)
|
||||
6 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_6, 0)
|
||||
7 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_7, 0)
|
||||
8 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_8, 0)
|
||||
9 -> sharedPreferences.getInt(Keys.PREF_PRESET_EQ_BAND_9, 0)
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
/* Loads preset Bass Boost */
|
||||
fun loadPresetBassBoost(): Float {
|
||||
return sharedPreferences.getFloat(Keys.PREF_PRESET_BASS_BOOST, 0f)
|
||||
}
|
||||
|
||||
/* Loads preset Reverb */
|
||||
fun loadPresetReverb(): Float {
|
||||
return sharedPreferences.getFloat(Keys.PREF_PRESET_REVERB, 0f)
|
||||
}
|
||||
|
||||
/* Loads preset DRC */
|
||||
fun loadPresetDrc(): Boolean {
|
||||
return sharedPreferences.getBoolean(Keys.PREF_PRESET_DRC, false)
|
||||
}
|
||||
|
||||
/* Loads preset Stereo Width */
|
||||
fun loadPresetStereoWidth(): Float {
|
||||
return sharedPreferences.getFloat(Keys.PREF_PRESET_STEREO_WIDTH, 1f)
|
||||
}
|
||||
|
||||
/* Resets Equalizer settings to default */
|
||||
fun resetEqualizer() {
|
||||
|
||||
Reference in New Issue
Block a user